📄 aic79xx.seq
字号:
* Rev A. Snapshot LQISTAT2 so the status is not missed * and deffer the test by one instruction. */ mov REG_ISR, LQISTAT2; test REG_ISR, LQIWORKONLQ jz main_isr; test SEQINTSRC, SAVEPTRS jz main_isr; test LONGJMP_ADDR[1], INVALID_ADDR jz saveptr_active_fifo; /* * Switch to the active FIFO after clearing the snapshot * savepointer in the current FIFO. We do this so that * a pending CTXTDONE or SAVEPTR is visible in the active * FIFO. This status is the only way we can detect if we * have lost the race (e.g. host paused us) and our attepts * to disable the channel occurred after all REQs were * already seen and acked (REQINIT never comes true). */ mvi DFFSXFRCTL, CLRCHN; xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1); test DFCNTRL, DIRECTION jz interrupt_return; and DFCNTRL, ~SCSIEN;snapshot_wait_data_valid: test SEQINTSRC, (CTXTDONE|SAVEPTRS) jnz snapshot_data_valid; test SSTAT1, REQINIT jz snapshot_wait_data_valid;snapshot_data_valid: or DFCNTRL, SCSIEN; or SEQINTCTL, IRET ret;snapshot_saveptr: mvi DFFSXFRCTL, CLRCHN; or SEQINTCTL, IRET ret;main_isr: } test SEQINTSRC, CFG4DATA jnz cfg4data_intr; test SEQINTSRC, CFG4ISTAT jnz cfg4istat_intr; test SEQINTSRC, SAVEPTRS jnz saveptr_intr; test SEQINTSRC, CFG4ICMD jnz cfg4icmd_intr; SET_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. On RTI capable controllers, * where snapshots can, and are, disabled, the code to handle this type * of snapshot is not active. * * The second case is a save pointers on an active FIFO which occurs * if the target changes to a new L_Q or busfrees/QASes 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: if ((ahd->features & AHD_RTI) == 0) { test LONGJMP_ADDR[1], INVALID_ADDR jnz snapshot_saveptr; }saveptr_active_fifo: and SEQIMODE, ~ENSAVEPTRS; or SEQINTCTL, IRET ret;cfg4data_intr: test SCB_SGPTR[0], SG_LIST_NULL jnz pkt_handle_overrun_inc_use_count; call load_first_seg; call pkt_handle_xfer; inc SCB_FIFO_USE_COUNT;interrupt_return: 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. */ SET_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. * If a command completed before an attempted * task management function completed, notify the host. */ test SCB_TASK_MANAGEMENT, 0xFF jz cfg4istat_no_taskmgmt_func; SET_SEQINTCODE(TASKMGMT_CMD_CMPLT_OKAY)cfg4istat_no_taskmgmt_func: call pkt_handle_status; or SEQINTCTL, IRET ret;cfg4icmd_intr: /* * In the case of DMAing a CDB from the host, the normal * CDB buffer is formatted with an 8 byte address followed * by a 1 byte count. */ bmov HADDR[0], SCB_HOST_CDB_PTR, 9; mvi SG_CACHE_PRE, LAST_SEG; mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN); call pkt_handle_cdb; 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 are 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: 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 pkt_last_seg_done; test SCSIPHASE, ~DATA_PHASE_MASK jz . + 2; test SCSISIGO, ATNO jnz . + 2; test SSTAT2, NONPACKREQ jz return; test MDFFSTAT, SHVALID jz return; /* FALLTHROUGH *//* * 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 this status and executing the common code for * these two cases. */pkt_saveptrs:BEGIN_CRITICAL; if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) { or DFCNTRL, FIFOFLUSH; } mov REG0, SEQINTSRC; call calc_residual; call save_pointers; mvi CLRSEQINTSRC, CLRSAVEPTRS; call disable_ccsgen; or SEQIMODE, ENSAVEPTRS; test DFCNTRL, DIRECTION jnz pkt_saveptrs_check_status; test DFSTATUS, FIFOEMP jnz pkt_saveptrs_check_status; /* * Keep a handler around for this FIFO until it drains * to the host to guarantee that we don't complete the * command to the host before the data arrives. */pkt_saveptrs_wait_fifoemp: call setjmp; test DFSTATUS, FIFOEMP jz return;pkt_saveptrs_check_status: or LONGJMP_ADDR[1], INVALID_ADDR; test REG0, SAVEPTRS jz unexpected_nonpkt_phase; dec SCB_FIFO_USE_COUNT; test SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle; mvi DFFSXFRCTL, CLRCHN ret;END_CRITICAL;/* * LAST_SEG_DONE status has been seen in the current FIFO. * This indicates that all of the allowed data for this * command has transferred across the SCSI and host buses. * Check for overrun and see if we can complete this command. */pkt_last_seg_done:BEGIN_CRITICAL; /* * Mark transfer as completed. */ or SCB_SGPTR, SG_LIST_NULL; /* * Wait for the current context to finish to verify that * no overrun condition has occurred. */ test SEQINTSRC, CTXTDONE jnz pkt_ctxt_done; call setjmp;pkt_wait_ctxt_done_loop: test SEQINTSRC, CTXTDONE jnz pkt_ctxt_done; /* * A sufficiently large overrun or a NONPACKREQ may * prevent CTXTDONE from ever asserting, so we must * poll for these statuses too. */ check_overrun; test SSTAT2, NONPACKREQ jz return; test SEQINTSRC, CTXTDONE jz unexpected_nonpkt_phase; /* FALLTHROUGH */pkt_ctxt_done: check_overrun; or LONGJMP_ADDR[1], INVALID_ADDR; /* * If status has been received, it is safe to skip * the check to see if another FIFO is active because * LAST_SEG_DONE has been observed. However, we check * the FIFO anyway since it costs us only one extra * instruction to leverage common code to perform the * SCB completion. */ dec SCB_FIFO_USE_COUNT; test SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle; mvi DFFSXFRCTL, CLRCHN ret;END_CRITICAL;/* * Must wait until CDB xfer is over before issuing the * clear channel. */pkt_handle_cdb: call setjmp; test SG_CACHE_SHADOW, LAST_SEG_DONE jz return; or LONGJMP_ADDR[1], INVALID_ADDR; mvi DFFSXFRCTL, CLRCHN ret;/* * Watch over the status transfer. Our host sense buffer is * large enough to take the maximum allowed status packet. * None-the-less, we must still catch and report overruns to * the host. Additionally, properly catch unexpected non-packet * phases that are typically caused by CRC errors in status packet * transmission. */pkt_handle_status: call setjmp; test SG_CACHE_SHADOW, LAST_SEG_DONE jnz pkt_status_check_overrun; test SEQINTSRC, CTXTDONE jz pkt_status_check_nonpackreq; test SG_CACHE_SHADOW, LAST_SEG_DONE jnz pkt_status_check_overrun;pkt_status_IU_done: if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) { or DFCNTRL, FIFOFLUSH; } test DFSTATUS, FIFOEMP jz return;BEGIN_CRITICAL; or LONGJMP_ADDR[1], INVALID_ADDR; mvi SCB_SCSI_STATUS, STATUS_PKT_SENSE; or SCB_CONTROL, STATUS_RCVD; jmp pkt_complete_scb_if_fifos_idle;END_CRITICAL;pkt_status_check_overrun: /* * Status PKT overruns are uncerimoniously recovered with a * bus reset. If we've overrun, let the host know so that * recovery can be performed. * * LAST_SEG_DONE has been observed. If either CTXTDONE or * a NONPACKREQ phase change have occurred and the FIFO is * empty, there is no overrun. */ test DFSTATUS, FIFOEMP jz pkt_status_report_overrun; test SEQINTSRC, CTXTDONE jz . + 2; test DFSTATUS, FIFOEMP jnz pkt_status_IU_done; test SCSIPHASE, ~DATA_PHASE_MASK jz return; test DFSTATUS, FIFOEMP jnz pkt_status_check_nonpackreq;pkt_status_report_overrun: SET_SEQINTCODE(STATUS_OVERRUN) /* SEQUENCER RESTARTED */pkt_status_check_nonpackreq: /* * CTXTDONE may be held off if a NONPACKREQ is associated with * the current context. If a NONPACKREQ is observed, decide * if it is for the current context. If it is for the current * context, we must defer NONPACKREQ processing until all data * has transferred to the host. */ test SCSIPHASE, ~DATA_PHASE_MASK jz return; test SCSISIGO, ATNO jnz . + 2; test SSTAT2, NONPACKREQ jz return; test SEQINTSRC, CTXTDONE jnz pkt_status_IU_done; test DFSTATUS, FIFOEMP jz return; /* * The unexpected nonpkt phase handler assumes that any * data channel use will have a FIFO reference count. It * turns out that the status handler doesn't need a refernce * count since the status received flag, and thus completion * processing, cannot be set until the handler is finished. * We increment the count here to make the nonpkt handler * happy. */ inc SCB_FIFO_USE_COUNT; /* FALLTHROUGH *//* * 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 unexpected_nonpkt_mode_cleared;SET_SRC_MODE M_DFF0;SET_DST_MODE M_DFF0; or LONGJMP_ADDR[1], INVALID_ADDR; dec SCB_FIFO_USE_COUNT; mvi DFFSXFRCTL, CLRCHN;unexpected_nonpkt_mode_cleared: mvi CLRSINT2, CLRNONPACKREQ; test SCSIPHASE, ~(MSG_IN_PHASE|MSG_OUT_PHASE) jnz illegal_phase; SET_SEQINTCODE(ENTERING_NONPACK) jmp ITloop;illegal_phase: SET_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_inc_use_count: inc SCB_FIFO_USE_COUNT;pkt_handle_overrun: SET_SEQINTCODE(CFG4OVERRUN) call freeze_queue; if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0) { or DFFSXFRCTL, DFFBITBUCKET;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, PRELOAD_AVAIL jz overrun_load_done; call load_overrun_buf; or DFCNTRL, PRELOADEN;overrun_load_done: test SEQINTSRC, CTXTDONE jnz pkt_overrun_end; } else { test DFFSXFRCTL, DFFBITBUCKET jz 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; dec SCB_FIFO_USE_COUNT; or LONGJMP_ADDR[1], INVALID_ADDR; test SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle; 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] ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -