📄 aic79xx.seq
字号:
* messages (save data pointers/disconnect and command * complete) that usually follow a data phase. */ call calc_residual; /* * Go ahead and shut down the DMA engine now. */ test DFCNTRL, DIRECTION jnz data_phase_finish;data_group_fifoflush: if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) { or DFCNTRL, FIFOFLUSH; } /* * We have enabled the auto-ack feature. This means * that the controller may have already transferred * some overrun bytes into the data FIFO and acked them * on the bus. The only way to detect this situation is * to wait for LAST_SEG_DONE to come true on a completed * transfer and then test to see if the data FIFO is * non-empty. We know there is more data yet to transfer * if SG_LIST_NULL is not yet set, thus there cannot be * an overrun. */ test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_finish; test SG_CACHE_SHADOW, LAST_SEG_DONE jz .; test DFSTATUS, FIFOEMP jnz data_phase_finish; /* Overrun */ jmp p_data;data_phase_finish: /* * If the target has left us in data phase, loop through * the dma code again. We will only loop if there is a * data overrun. */ if ((ahd->flags & AHD_TARGETROLE) != 0) { test SSTAT0, TARGET jnz data_phase_done; } if ((ahd->flags & AHD_INITIATORROLE) != 0) { test SSTAT1, REQINIT jz .; test SCSIPHASE, DATA_PHASE_MASK jnz p_data; }data_phase_done: /* Kill off any pending prefetch */ call disable_ccsgen; if ((ahd->flags & AHD_TARGETROLE) != 0) { test SEQ_FLAGS, DPHASE_PENDING jz ITloop; /* and SEQ_FLAGS, ~DPHASE_PENDING; * For data-in phases, wait for any pending acks from the * initiator before changing phase. We only need to * send Ignore Wide Residue messages for data-in phases. test DFCNTRL, DIRECTION jz target_ITloop; test SSTAT1, REQINIT jnz .; test DATA_COUNT_ODD, 0x1 jz target_ITloop; SET_MODE(M_SCSI, M_SCSI); test NEGCONOPTS, WIDEXFER jz target_ITloop; */ /* * Issue an Ignore Wide Residue Message. mvi P_MESGIN|BSYO call change_phase; mvi MSG_IGN_WIDE_RESIDUE call target_outb; mvi 1 call target_outb; jmp target_ITloop; */ } else { jmp ITloop; }/* * We assume that, even though data may still be * transferring to the host, that the SCSI side of * the DMA engine is now in a static state. This * allows us to update our notion of where we are * in this transfer. * * If, by chance, we stopped before being able * to fetch additional segments for this transfer, * yet the last S/G was completely exhausted, * call our idle loop until it is able to load * another segment. This will allow us to immediately * pickup on the next segment on the next data phase. * * If we happened to stop on the last segment, then * our residual information is still correct from * the idle loop and there is no need to perform * any fixups. */calc_residual: test SG_CACHE_SHADOW, LAST_SEG jz residual_before_last_seg; /* Record if we've consumed all S/G entries */ test MDFFSTAT, SHVALID jz . + 2; bmov SCB_RESIDUAL_DATACNT, SHCNT, 3 ret; or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL ret;residual_before_last_seg: test MDFFSTAT, SHVALID jnz sgptr_fixup; /* * Can never happen from an interrupt as the packetized * hardware will only interrupt us once SHVALID or * LAST_SEG_DONE. */ call data_group_idle_loop; jmp calc_residual;sgptr_fixup: /* * Fixup the residual next S/G pointer. The S/G preload * feature of the chip allows us to load two elements * in addition to the currently active element. We * store the bottom byte of the next S/G pointer in * the SG_CACHE_PTR register so we can restore the * correct value when the DMA completes. If the next * sg ptr value has advanced to the point where higher * bytes in the address have been affected, fix them * too. */ test SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done; test SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done; add SCB_RESIDUAL_SGPTR[1], -1; adc SCB_RESIDUAL_SGPTR[2], -1; adc SCB_RESIDUAL_SGPTR[3], -1;sgptr_fixup_done: and SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW; clr DATA_COUNT_ODD; test SG_CACHE_SHADOW, ODD_SEG jz . + 2; or DATA_COUNT_ODD, 0x1; clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */ bmov SCB_RESIDUAL_DATACNT, SHCNT, 3 ret;export seq_isr: nop; /* Jumps in the first ISR instruction fail on Rev A. */ test SEQINTSRC, SAVEPTRS jnz saveptr_intr; test SEQINTSRC, CFG4DATA jnz cfg4data_intr; test SEQINTSRC, CFG4ISTAT jnz cfg4istat_intr; test SEQINTSRC, CFG4ICMD jnz cfg4icmd_intr; mvi SEQINTCODE, INVALID_SEQINT;/* * There are two types of save pointers interrupts: * The first is a snapshot save pointers where the current FIFO is not * active and contains a snapshot of the current poniter information. * This happens between packets in a stream for a single L_Q. Since we * are not performing a pointer save, we can safely clear the channel * so it can be used for other transactions. * * The second case is a save pointers on an active FIFO which occurs * if the target changes to a new L_Q or busfrees/QAS' and the transfer * has a residual. This should occur coincident with a ctxtdone. We * disable the interrupt and allow our active routine to handle the * save. */saveptr_intr: test DFCNTRL, HDMAENACK jz snapshot_saveptr; and SEQIMODE, ~ENSAVEPTRS; or SEQINTCTL, IRET ret;snapshot_saveptr: mvi DFFSXFRCTL, CLRCHN; or SEQINTCTL, IRET ret;cfg4data_intr: test SCB_SGPTR[0], SG_LIST_NULL jnz pkt_handle_overrun; call load_first_seg; call pkt_handle_xfer; or SEQINTCTL, IRET ret;cfg4istat_intr: call freeze_queue; add NONE, -13, SCB_CDB_LEN; jnc cfg4istat_have_sense_addr; test SCB_CDB_LEN, SCB_CDB_LEN_PTR jnz cfg4istat_have_sense_addr; /* * Host sets up address/count and enables transfer. */ mvi SEQINTCODE, CFG4ISTAT_INTR; jmp cfg4istat_setup_handler;cfg4istat_have_sense_addr: bmov HADDR, SCB_SENSE_BUSADDR, 4; mvi HCNT[1], (AHD_SENSE_BUFSIZE >> 8); mvi SG_CACHE_PRE, LAST_SEG; mvi DFCNTRL, PRELOADEN|SCSIEN|HDMAEN;cfg4istat_setup_handler: /* * Status pkt is transferring to host. * Wait in idle loop for transfer to complete. */ call pkt_handle_status; or SEQINTCTL, IRET ret;/* * See if the target has gone on in this context creating an * overrun condition. For the write case, the hardware cannot * ack bytes until data is provided. So, if the target begins * another packet without changing contexts, implying we are * not sitting on a packet boundary, we are in an overrun * situation. For the read case, the hardware will continue to * ack bytes into the FIFO, and may even ack the last overrun packet * into the FIFO. If the FIFO should become non-empty, we are in * a read overrun case. */#define check_overrun \ /* Not on a packet boundary. */ \ test MDFFSTAT, DLZERO jz pkt_handle_overrun; \ test DFSTATUS, FIFOEMP jz pkt_handle_overrunpkt_handle_xfer: bmov LONGJMP_SCB, SCBPTR, 2; test SG_STATE, LOADING_NEEDED jz pkt_last_seg; call setjmp; test SEQINTSRC, SAVEPTRS jnz pkt_saveptrs; test SCSIPHASE, ~DATA_PHASE_MASK jz . + 2; test SCSISIGO, ATNO jnz . + 2; test SSTAT2, NONPACKREQ jz pkt_service_fifo; /* * Defer handling of this NONPACKREQ until we * can be sure it pertains to this FIFO. SAVEPTRS * will not be asserted if the NONPACKREQ is for us, * so we must simulate it if shaddow is valid. If * shaddow is not valid, keep running this FIFO until we * have satisfied the transfer by loading segments and * waiting for either shaddow valid or last_seg_done. */ test MDFFSTAT, SHVALID jnz pkt_saveptrs;pkt_service_fifo: test SG_STATE, LOADING_NEEDED jnz service_fifo;pkt_last_seg: call setjmp; test SEQINTSRC, SAVEPTRS jnz pkt_saveptrs; test SG_CACHE_SHADOW, LAST_SEG_DONE jnz last_pkt_done; test SCSIPHASE, ~DATA_PHASE_MASK jz . + 2; test SCSISIGO, ATNO jnz . + 2; test SSTAT2, NONPACKREQ jz return; test MDFFSTAT, SHVALID jnz pkt_saveptrs; jmp return;last_pkt_done:BEGIN_CRITICAL; if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) { or DFCNTRL, FIFOFLUSH; } test SCB_CONTROL, STATUS_RCVD jz wait_pkt_end; check_overrun; or SCB_SGPTR, SG_LIST_NULL; /* * I think it is safe to skip the FIFO check. * in this case as LAST_SEG_DONE implies * the other FIFO, if ever active for this transfer, * has completed. */last_pkt_queue_scb: or LONGJMP_ADDR[1], INVALID_ADDR; bmov ARG_1, SCBPTR, 2; mvi DFFSXFRCTL, CLRCHN; jmp queue_arg1_scb_completion;last_pkt_complete: bmov ARG_1, SCBPTR, 2; mvi DFFSXFRCTL, CLRCHN;check_other_fifo: clc; call toggle_dff_mode; call check_fifo; jnc queue_arg1_scb_completion;return: ret;wait_pkt_end: call setjmp;END_CRITICAL;wait_pkt_end_loop: test SEQINTSRC, CTXTDONE jnz pkt_end; check_overrun; test SSTAT2, NONPACKREQ jz return; test SEQINTSRC, CTXTDONE jz unexpected_nonpkt_phase;pkt_end:BEGIN_CRITICAL; check_overrun; or LONGJMP_ADDR[1], INVALID_ADDR; or SCB_SGPTR, SG_LIST_NULL; test SCB_CONTROL, STATUS_RCVD jnz last_pkt_complete; mvi DFFSXFRCTL, CLRCHN ret;END_CRITICAL;/* * Either a SAVEPTRS interrupt condition is pending for this FIFO * or we have a pending nonpackreq for this FIFO. We differentiate * between the two by capturing the state of the SAVEPTRS interrupt * prior to clearing and handling the common code of these two cases. */pkt_saveptrs:BEGIN_CRITICAL; if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) { or DFCNTRL, FIFOFLUSH; } mov REG0, SEQINTSRC; mvi CLRSEQINTSRC, CLRSAVEPTRS; call calc_residual; call save_pointers; call disable_ccsgen; or SEQIMODE, ENSAVEPTRS; or LONGJMP_ADDR[1], INVALID_ADDR;pkt_saveptrs_check_status: test REG0, SAVEPTRS jz unexpected_nonpkt_phase; test SCB_CONTROL, STATUS_RCVD jz pkt_saveptrs_clrchn; jmp last_pkt_complete;pkt_saveptrs_clrchn: mvi DFFSXFRCTL, CLRCHN ret;END_CRITICAL;check_status_overrun: test SHCNT[2], 0xFF jz status_IU_done; mvi SEQINTCODE, STATUS_OVERRUN; jmp status_IU_done;pkt_handle_status: call setjmp_setscb; test MDFFSTAT, LASTSDONE jnz check_status_overrun; test SEQINTSRC, CTXTDONE jz return;status_IU_done:BEGIN_CRITICAL; if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) { or DFCNTRL, FIFOFLUSH; } or LONGJMP_ADDR[1], INVALID_ADDR; mvi SCB_SCSI_STATUS, STATUS_PKT_SENSE; or SCB_CONTROL, STATUS_RCVD; jmp last_pkt_complete;END_CRITICAL;SET_SRC_MODE M_DFF0;SET_DST_MODE M_DFF0;BEGIN_CRITICAL;check_fifo: test LONGJMP_ADDR[1], INVALID_ADDR jnz return; mov A, ARG_2; cmp LONGJMP_SCB[1], A jne return; mov A, ARG_1; cmp LONGJMP_SCB[0], A jne return; stc ret;END_CRITICAL;/* * Nonpackreq is a polled status. It can come true in three situations: * we have received an L_Q, we have sent one or more L_Qs, or there is no * L_Q context associated with this REQ (REQ occurs immediately after a * (re)selection). Routines that know that the context responsible for this * nonpackreq call directly into unexpected_nonpkt_phase. In the case of the * top level idle loop, we exhaust all active contexts prior to determining that * we simply do not have the full I_T_L_Q for this phase. */unexpected_nonpkt_phase_find_ctxt: /* * This nonpackreq is most likely associated with one of the tags * in a FIFO or an outgoing LQ. Only treat it as an I_T only * nonpackreq if we've cleared out the FIFOs and handled any * pending SELDO. */SET_SRC_MODE M_SCSI;SET_DST_MODE M_SCSI; and A, FIFO1FREE|FIFO0FREE, DFFSTAT; cmp A, FIFO1FREE|FIFO0FREE jne return; test SSTAT0, SELDO jnz return; mvi SCBPTR[1], SCB_LIST_NULL;unexpected_nonpkt_phase: test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) jnz . + 3;SET_SRC_MODE M_DFF0;SET_DST_MODE M_DFF0; or LONGJMP_ADDR[1], INVALID_ADDR; mvi DFFSXFRCTL, CLRCHN; mvi CLRSINT2, CLRNONPACKREQ; test SCSIPHASE, ~(MSG_IN_PHASE|MSG_OUT_PHASE) jnz illegal_phase; mvi SEQINTCODE, ENTERING_NONPACK; jmp ITloop;illegal_phase: mvi SEQINTCODE, ILLEGAL_PHASE; jmp ITloop;/* * We have entered an overrun situation. If we have working * BITBUCKET, flip that on and let the hardware eat any overrun * data. Otherwise use an overrun buffer in the host to simulate * BITBUCKET. */pkt_handle_overrun: mvi SEQINTCODE, CFG4OVERRUN; call freeze_queue; if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0) { SET_MODE(M_SCSI, M_SCSI); or SXFRCTL1,BITBUCKET;SET_SRC_MODE M_DFF1;SET_DST_MODE M_DFF1; } else { call load_overrun_buf; mvi DFCNTRL, (HDMAEN|SCSIEN|PRELOADEN); } call setjmp; if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) { test DFSTATUS, PKT_PRELOAD_AVAIL jz overrun_load_done; call load_overrun_buf; or DFCNTRL, PRELOADEN;overrun_load_done: } test SEQINTSRC, CTXTDONE jnz pkt_overrun_end; test SSTAT2, NONPACKREQ jz return;pkt_overrun_end: or SCB_RESIDUAL_SGPTR, SG_OVERRUN_RESID; test SEQINTSRC, CTXTDONE jz unexpected_nonpkt_phase; test SCB_CONTROL, STATUS_RCVD jnz last_pkt_queue_scb; mvi DFFSXFRCTL, CLRCHN ret;if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) {load_overrun_buf: /* * Load a dummy segment if preload space is available. */ mov HADDR[0], SHARED_DATA_ADDR; add HADDR[1], PKT_OVERRUN_BUFOFFSET, SHARED_DATA_ADDR[1]; mov ACCUM_SAVE, A; clr A; adc HADDR[2], A, SHARED_DATA_ADDR[2]; adc HADDR[3], A, SHARED_DATA_ADDR[3]; mov A, ACCUM_SAVE; bmov HADDR[4], ALLZEROS, 4; /* PKT_OVERRUN_BUFSIZE is a multiple of 256 */ clr HCNT[0]; mvi HCNT[1], ((PKT_OVERRUN_BUFSIZE >> 8) & 0xFF); clr HCNT[2];}cfg4icmd_intr:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -