📄 aic79xx.seq
字号:
scbdma_idle: /* * Don't bother downloading new SCBs to execute * if select-outs are currently frozen or we have * a MK_MESSAGE SCB waiting to enter the queue. */ test SEQ_FLAGS2, SELECTOUT_QFROZEN|PENDING_MK_MESSAGE jnz scbdma_no_new_scbs;BEGIN_CRITICAL; test QOFF_CTLSTA, NEW_SCB_AVAIL jnz fetch_new_scb;scbdma_no_new_scbs: cmp COMPLETE_DMA_SCB_HEAD[1], SCB_LIST_NULL jne dma_complete_scb; cmp COMPLETE_SCB_HEAD[1], SCB_LIST_NULL je return; /* FALLTHROUGH */fill_qoutfifo: /* * Keep track of the SCBs we are dmaing just * in case the DMA fails or is aborted. */ bmov COMPLETE_SCB_DMAINPROG_HEAD, COMPLETE_SCB_HEAD, 2; mvi CCSCBCTL, CCSCBRESET; bmov SCBHADDR, QOUTFIFO_NEXT_ADDR, 4; mov A, QOUTFIFO_NEXT_ADDR; bmov SCBPTR, COMPLETE_SCB_HEAD, 2;fill_qoutfifo_loop: bmov CCSCBRAM, SCBPTR, 2; mov CCSCBRAM, SCB_SGPTR[0]; mov CCSCBRAM, QOUTFIFO_ENTRY_VALID_TAG; mov NONE, SDSCB_QOFF; inc INT_COALESCING_CMDCOUNT; add CMDS_PENDING, -1; adc CMDS_PENDING[1], -1; cmp SCB_NEXT_COMPLETE[1], SCB_LIST_NULL je fill_qoutfifo_done; cmp CCSCBADDR, CCSCBADDR_MAX je fill_qoutfifo_done; test QOFF_CTLSTA, SDSCB_ROLLOVR jnz fill_qoutfifo_done; /* * Don't cross an ADB or Cachline boundary when DMA'ing * completion entries. In PCI mode, at least in 32/33 * configurations, the SCB DMA engine may lose its place * in the data-stream should the target force a retry on * something other than an 8byte aligned boundary. In * PCI-X mode, we do this to avoid split transactions since * many chipsets seem to be unable to format proper split * completions to continue the data transfer. */ add SINDEX, A, CCSCBADDR; test SINDEX, CACHELINE_MASK jz fill_qoutfifo_done; bmov SCBPTR, SCB_NEXT_COMPLETE, 2; jmp fill_qoutfifo_loop;fill_qoutfifo_done: mov SCBHCNT, CCSCBADDR; mvi CCSCBCTL, CCSCBEN|CCSCBRESET; bmov COMPLETE_SCB_HEAD, SCB_NEXT_COMPLETE, 2; mvi SCB_NEXT_COMPLETE[1], SCB_LIST_NULL ret;fetch_new_scb: bmov SCBHADDR, NEXT_QUEUED_SCB_ADDR, 4; mvi CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET jmp dma_scb;dma_complete_scb: bmov SCBPTR, COMPLETE_DMA_SCB_HEAD, 2; bmov SCBHADDR, SCB_BUSADDR, 4; mvi CCARREN|CCSCBEN|CCSCBRESET jmp dma_scb;/* * Either post or fetch an SCB from host memory. The caller * is responsible for polling for transfer completion. * * Prerequisits: Mode == M_CCHAN * SINDEX contains CCSCBCTL flags * SCBHADDR set to Host SCB address * SCBPTR set to SCB src location on "push" operations */SET_SRC_MODE M_CCHAN;SET_DST_MODE M_CCHAN;dma_scb: mvi SCBHCNT, SCB_TRANSFER_SIZE; mov CCSCBCTL, SINDEX ret;setjmp: /* * At least on the A, a return in the same * instruction as the bmov results in a return * to the caller, not to the new address at the * top of the stack. Since we want the latter * (we use setjmp to register a handler from an * interrupt context but not invoke that handler * until we return to our idle loop), use a * separate ret instruction. */ bmov LONGJMP_ADDR, STACK, 2; ret;setjmp_inline: bmov LONGJMP_ADDR, STACK, 2;longjmp: bmov STACK, LONGJMP_ADDR, 2 ret;END_CRITICAL;/*************************** Chip Bug Work Arounds ****************************//* * Must disable interrupts when setting the mode pointer * register as an interrupt occurring mid update will * fail to store the new mode value for restoration on * an iret. */if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) {set_mode_work_around: mvi SEQINTCTL, INTVEC1DSL; mov MODE_PTR, SINDEX; clr SEQINTCTL ret;}if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {set_seqint_work_around: mov SEQINTCODE, SINDEX; mvi SEQINTCODE, NO_SEQINT ret;}/************************ Packetized LongJmp Routines *************************/SET_SRC_MODE M_SCSI;SET_DST_MODE M_SCSI;start_selection:BEGIN_CRITICAL; if ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0) { /* * Razor #494 * Rev A hardware fails to update LAST/CURR/NEXTSCB * correctly after a packetized selection in several * situations: * * 1) If only one command existed in the queue, the * LAST/CURR/NEXTSCB are unchanged. * * 2) In a non QAS, protocol allowed phase change, * the queue is shifted 1 too far. LASTSCB is * the last SCB that was correctly processed. * * 3) In the QAS case, if the full list of commands * was successfully sent, NEXTSCB is NULL and neither * CURRSCB nor LASTSCB can be trusted. We must * manually walk the list counting MAXCMDCNT elements * to find the last SCB that was sent correctly. * * To simplify the workaround for this bug in SELDO * handling, we initialize LASTSCB prior to enabling * selection so we can rely on it even for case #1 above. */ bmov LASTSCB, WAITING_TID_HEAD, 2; } bmov CURRSCB, WAITING_TID_HEAD, 2; bmov SCBPTR, WAITING_TID_HEAD, 2; shr SELOID, 4, SCB_SCSIID; /* * If we want to send a message to the device, ensure * we are selecting with atn irregardless of our packetized * agreement. Since SPI4 only allows target reset or PPR * messages if this is a packetized connection, the change * to our negotiation table entry for this selection will * be cleared when the message is acted on. */ test SCB_CONTROL, MK_MESSAGE jz . + 3; mov NEGOADDR, SELOID; or NEGCONOPTS, ENAUTOATNO; or SCSISEQ0, ENSELO ret;END_CRITICAL;/* * Allocate a FIFO for a non-packetized transaction. * In RevA hardware, both FIFOs must be free before we * can allocate a FIFO for a non-packetized transaction. */allocate_fifo_loop: /* * Do whatever work is required to free a FIFO. */ call idle_loop_service_fifos; SET_MODE(M_SCSI, M_SCSI)allocate_fifo: if ((ahd->bugs & AHD_NONPACKFIFO_BUG) != 0) { and A, FIFO0FREE|FIFO1FREE, DFFSTAT; cmp A, FIFO0FREE|FIFO1FREE jne allocate_fifo_loop; } else { test DFFSTAT, FIFO1FREE jnz allocate_fifo1; test DFFSTAT, FIFO0FREE jz allocate_fifo_loop; mvi DFFSTAT, B_CURRFIFO_0; SET_MODE(M_DFF0, M_DFF0) bmov SCBPTR, ALLOCFIFO_SCBPTR, 2 ret; }SET_SRC_MODE M_SCSI;SET_DST_MODE M_SCSI;allocate_fifo1: mvi DFFSTAT, CURRFIFO_1; SET_MODE(M_DFF1, M_DFF1) bmov SCBPTR, ALLOCFIFO_SCBPTR, 2 ret;/* * We have been reselected as an initiator * or selected as a target. */SET_SRC_MODE M_SCSI;SET_DST_MODE M_SCSI;select_in: if ((ahd->bugs & AHD_FAINT_LED_BUG) != 0) { /* * On Rev A. hardware, the busy LED is only * turned on automaically during selections * and re-selections. Make the LED status * more useful by forcing it to be on from * the point of selection until our idle * loop determines that neither of our FIFOs * are busy. This handles the non-packetized * case nicely as we will not return to the * idle loop until the busfree at the end of * each transaction. */ or SBLKCTL, DIAGLEDEN|DIAGLEDON; } if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) { /* * Test to ensure that the bus has not * already gone free prior to clearing * any stale busfree status. This avoids * a window whereby a busfree just after * a selection could be missed. */ test SCSISIGI, BSYI jz . + 2; mvi CLRSINT1,CLRBUSFREE; or SIMODE1, ENBUSFREE; } or SXFRCTL0, SPIOEN; and SAVED_SCSIID, SELID_MASK, SELID; and A, OID, IOWNID; or SAVED_SCSIID, A; mvi CLRSINT0, CLRSELDI; jmp ITloop;/* * We have successfully selected out. * * Clear SELDO. * Dequeue all SCBs sent from the waiting queue * Requeue all SCBs *not* sent to the tail of the waiting queue * Take Razor #494 into account for above. * * In Packetized Mode: * Return to the idle loop. Our interrupt handler will take * care of any incoming L_Qs. * * In Non-Packetize Mode: * Continue to our normal state machine. */SET_SRC_MODE M_SCSI;SET_DST_MODE M_SCSI;select_out:BEGIN_CRITICAL; if ((ahd->bugs & AHD_FAINT_LED_BUG) != 0) { /* * On Rev A. hardware, the busy LED is only * turned on automaically during selections * and re-selections. Make the LED status * more useful by forcing it to be on from * the point of re-selection until our idle * loop determines that neither of our FIFOs * are busy. This handles the non-packetized * case nicely as we will not return to the * idle loop until the busfree at the end of * each transaction. */ or SBLKCTL, DIAGLEDEN|DIAGLEDON; } /* Clear out all SCBs that have been successfully sent. */ if ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0) { /* * For packetized, the LQO manager clears ENSELO on * the assertion of SELDO. If we are non-packetized, * LASTSCB and CURRSCB are accurate. */ test SCSISEQ0, ENSELO jnz use_lastscb; /* * The update is correct for LQOSTAT1 errors. All * but LQOBUSFREE are handled by kernel interrupts. * If we see LQOBUSFREE, return to the idle loop. * Once we are out of the select_out critical section, * the kernel will cleanup the LQOBUSFREE and we will * eventually restart the selection if appropriate. */ test LQOSTAT1, LQOBUSFREE jnz idle_loop; /* * On a phase change oustside of packet boundaries, * LASTSCB points to the currently active SCB context * on the bus. */ test LQOSTAT2, LQOPHACHGOUTPKT jnz use_lastscb; /* * If the hardware has traversed the whole list, NEXTSCB * will be NULL, CURRSCB and LASTSCB cannot be trusted, * but MAXCMDCNT is accurate. If we stop part way through * the list or only had one command to issue, NEXTSCB[1] is * not NULL and LASTSCB is the last command to go out. */ cmp NEXTSCB[1], SCB_LIST_NULL jne use_lastscb; /* * Brute force walk. */ bmov SCBPTR, WAITING_TID_HEAD, 2; mvi SEQINTCTL, INTVEC1DSL; mvi MODE_PTR, MK_MODE(M_CFG, M_CFG); mov A, MAXCMDCNT; mvi MODE_PTR, MK_MODE(M_SCSI, M_SCSI); clr SEQINTCTL;find_lastscb_loop: dec A; test A, 0xFF jz found_last_sent_scb; bmov SCBPTR, SCB_NEXT, 2; jmp find_lastscb_loop;use_lastscb: bmov SCBPTR, LASTSCB, 2;found_last_sent_scb: bmov CURRSCB, SCBPTR, 2;curscb_ww_done: } else { bmov SCBPTR, CURRSCB, 2; } /* * The whole list made it. Clear our tail pointer to indicate * that the per-target selection queue is now empty. */ cmp SCB_NEXT[1], SCB_LIST_NULL je select_out_clear_tail; /* * Requeue any SCBs not sent, to the tail of the waiting Q. * We know that neither the per-TID list nor the list of * TIDs is empty. Use this knowledge to our advantage and * queue the remainder to the tail of the global execution * queue. */ bmov REG0, SCB_NEXT, 2;select_out_queue_remainder: bmov SCBPTR, WAITING_TID_TAIL, 2; bmov SCB_NEXT2, REG0, 2; bmov WAITING_TID_TAIL, REG0, 2; jmp select_out_inc_tid_q;select_out_clear_tail: /* * Queue any pending MK_MESSAGE SCB for this target now * that the queue is empty. */ test SEQ_FLAGS2, PENDING_MK_MESSAGE jz select_out_no_mk_message_scb; mov A, MK_MESSAGE_SCSIID; cmp SCB_SCSIID, A jne select_out_no_mk_message_scb; and SEQ_FLAGS2, ~PENDING_MK_MESSAGE; bmov REG0, MK_MESSAGE_SCB, 2; jmp select_out_queue_remainder;select_out_no_mk_message_scb: /* * Clear this target's execution tail and increment the queue. */ shr DINDEX, 3, SCB_SCSIID; or DINDEX, 1; /* Want only the second byte */ mvi DINDEX[1], ((WAITING_SCB_TAILS) >> 8); mvi DINDIR, SCB_LIST_NULL;select_out_inc_tid_q: bmov SCBPTR, WAITING_TID_HEAD, 2; bmov WAITING_TID_HEAD, SCB_NEXT2, 2; cmp WAITING_TID_HEAD[1], SCB_LIST_NULL jne . + 2; mvi WAITING_TID_TAIL[1], SCB_LIST_NULL; bmov SCBPTR, CURRSCB, 2; mvi CLRSINT0, CLRSELDO; test LQOSTAT2, LQOPHACHGOUTPKT jnz unexpected_nonpkt_mode_cleared; test LQOSTAT1, LQOPHACHGINPKT jnz unexpected_nonpkt_mode_cleared; /* * If this is a packetized connection, return to our * idle_loop and let our interrupt handler deal with * any connection setup/teardown issues. The only * exceptions are the case of MK_MESSAGE and task management * SCBs. */ if ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0) { /* * In the A, the LQO manager transitions to LQOSTOP0 even if * we have selected out with ATN asserted and the target * REQs in a non-packet phase. */ test SCB_CONTROL, MK_MESSAGE jz select_out_no_message; test SCSISIGO, ATNO jnz select_out_non_packetized;select_out_no_message: } test LQOSTAT2, LQOSTOP0 jz select_out_non_packetized; test SCB_TASK_MANAGEMENT, 0xFF jz idle_loop; SET_SEQINTCODE(TASKMGMT_FUNC_COMPLETE) jmp idle_loop;select_out_non_packetized: /* Non packetized request. */ and SCSISEQ0, ~ENSELO; if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) { /* * Test to ensure that the bus has not * already gone free prior to clearing * any stale busfree status. This avoids * a window whereby a busfree just after * a selection could be missed. */ test SCSISIGI, BSYI jz . + 2; mvi CLRSINT1,CLRBUSFREE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -