📄 aic7xxx.seq
字号:
mvi STCNT[1], 0xFF; mvi STCNT[2], 0xFF; }data_phase_inbounds:/* If we are the last SG block, tell the hardware. */ cmp SG_COUNT,0x01 jne data_phase_wideodd; if ((p->features & AHC_ULTRA2) != 0) { or SG_CACHEPTR, LAST_SEG; } else { and DMAPARAMS, ~WIDEODD; }data_phase_wideodd: if ((p->features & AHC_ULTRA2) != 0) { mov SINDEX, ALLONES; mov DFCNTRL, DMAPARAMS; test SSTAT0, SDONE jnz .;/* Wait for preload to complete */data_phase_dma_loop: test SSTAT0, SDONE jnz data_phase_dma_done; test SSTAT1,PHASEMIS jz data_phase_dma_loop; /* ie. underrun */data_phase_dma_phasemis: test SSTAT0,SDONE jnz . + 2; mov SINDEX,ALLZEROS; /* Remeber the phasemiss */ } else { mov DMAPARAMS call dma; }data_phase_dma_done:/* Go tell the host about any overruns */ test SXFRCTL1,BITBUCKET jnz data_phase_overrun;/* Exit if we had an underrun. dma clears SINDEX in this case. */ test SINDEX,0xff jz data_phase_finish;/* * Advance the scatter-gather pointers if needed */sg_advance: dec SG_COUNT; /* one less segment to go */ test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? *//* * Load a struct scatter and set up the data address and length. * If the working value of the SG count is nonzero, then * we need to load a new set of values. * * This, like all DMA's, assumes little-endian host data storage. */sg_load: if ((p->features & AHC_CMD_CHAN) != 0) { /* * Do we have any prefetch left??? */ cmp CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail; /* * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes. */ add A, -(CCSGRAM_MAXSEGS + 1), SG_COUNT; mvi A, CCSGADDR_MAX; jc . + 2; shl A, 3, SG_COUNT; mov CCHCNT, A; bmov CCHADDR, SG_NEXT, 4; mvi CCSGCTL, CCSGEN|CCSGRESET; test CCSGCTL, CCSGDONE jz .; and CCSGCTL, ~CCSGEN; test CCSGCTL, CCSGEN jnz .; mvi CCSGCTL, CCSGRESET;prefetched_segs_avail: bmov HADDR, CCSGRAM, 8; } else { mvi DINDEX, HADDR; mvi SG_NEXT call bcopy_4; mvi HCNT[0],SG_SIZEOF; clr HCNT[1]; clr HCNT[2]; or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; call dma_finish; /* * Copy data from FIFO into SCB data pointer and data count. * This assumes that the SG segments are of the form: * struct ahc_dma_seg { * u_int32_t addr; four bytes, little-endian order * u_int32_t len; four bytes, little endian order * }; */ mvi HADDR call dfdat_in_7; } if ((p->features & AHC_ULTRA2) == 0) { /* Load STCNT as well. It is a mirror of HCNT */ call set_stcnt_from_hcnt; }/* Advance the SG pointer */ clr A; /* add sizeof(struct scatter) */ add SG_NEXT[0],SG_SIZEOF; adc SG_NEXT[1],A; test SSTAT1,PHASEMIS jz data_phase_loop; /* Ensure the last seg is visable at the shaddow layer */ if ((p->features & AHC_ULTRA2) != 0) { or DFCNTRL, PRELOADEN; }data_phase_finish: if ((p->features & AHC_ULTRA2) != 0) { call ultra2_dmafinish; }/* * After a DMA finishes, save the SG and STCNT residuals back into the SCB * We use STCNT instead of HCNT, since it's a reflection of how many bytes * were transferred on the SCSI (as opposed to the host) bus. */ mov SCB_RESID_DCNT[0],STCNT[0]; mov SCB_RESID_DCNT[1],STCNT[1]; mov SCB_RESID_DCNT[2],STCNT[2]; mov SCB_RESID_SGCNT, SG_COUNT; if ((p->features & AHC_ULTRA2) != 0) { or SXFRCTL0, CLRSTCNT|CLRCHN; } jmp ITloop;data_phase_overrun: if ((p->features & AHC_ULTRA2) != 0) { call ultra2_dmafinish; or SXFRCTL0, CLRSTCNT|CLRCHN; }/* * Turn off BITBUCKET mode and notify the host */ and SXFRCTL1, ~BITBUCKET; mvi INTSTAT,DATA_OVERRUN; jmp ITloop;ultra2_dmafinish: if ((p->features & AHC_ULTRA2) != 0) { test DFCNTRL, DIRECTION jnz ultra2_dmahalt; and DFCNTRL, ~SCSIEN; test DFCNTRL, SCSIEN jnz .; or DFCNTRL, FIFOFLUSH; test DFSTATUS, FIFOEMP jz . - 1;ultra2_dmahalt: and DFCNTRL, ~(SCSIEN|HDMAEN); test DFCNTRL, HDMAEN jnz .; ret; }/* * Command phase. Set up the DMA registers and let 'er rip. */p_command: call assert;/* * Load HADDR and HCNT. */ if ((p->features & AHC_ULTRA2) != 0) { or SG_CACHEPTR, LAST_SEG; } if ((p->features & AHC_CMD_CHAN) != 0) { bmov HADDR, SCB_CMDPTR, 5; bmov HCNT[1], ALLZEROS, 2; } else { mvi DINDEX, HADDR; mvi SCB_CMDPTR call bcopy_5; clr HCNT[1]; clr HCNT[2]; } if ((p->features & AHC_ULTRA2) == 0) { call set_stcnt_from_hcnt; mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma; } else { mvi (PRELOADEN|SCSIEN|HDMAEN|DIRECTION) call dma; } jmp ITloop;/* * Status phase. Wait for the data byte to appear, then read it * and store it into the SCB. */p_status: call assert; mov SCB_TARGET_STATUS, SCSIDATL; jmp ITloop;/* * Message out phase. If MSG_OUT is 0x80, build I full indentify message * sequence and send it to the target. In addition, if the MK_MESSAGE bit * is set in the SCB_CONTROL byte, interrupt the host and allow it to send * it's own message. * * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message. * This is done to allow the hsot to send messages outside of an identify * sequence while protecting the seqencer from testing the MK_MESSAGE bit * on an SCB that might not be for the current nexus. (For example, a * BDR message in responce to a bad reselection would leave us pointed to * an SCB that doesn't have anything to do with the current target). * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, * bus device reset). * * When there are no messages to send, MSG_OUT should be set to MSG_NOOP, * in case the target decides to put us in this phase for some strange * reason. */p_mesgout: mov SINDEX, MSG_OUT; cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;p_mesgout_identify: if ((p->features & AHC_WIDE) != 0) { and SINDEX,0xf,SCB_TCL; /* lun */ } else { and SINDEX,0x7,SCB_TCL; /* lun */ } and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */ or SINDEX,A; /* or in disconnect privledge */ or SINDEX,MSG_IDENTIFYFLAG;p_mesgout_mk_message: test SCB_CONTROL,MK_MESSAGE jz p_mesgout_tag; mov SCSIDATL, SINDEX; /* Send the last byte */ jmp p_mesgout_from_host + 1;/* Skip HOST_MSG test *//* * Send a tag message if TAG_ENB is set in the SCB control block. * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. */p_mesgout_tag: test SCB_CONTROL,TAG_ENB jz p_mesgout_onebyte; mov SCSIDATL, SINDEX; /* Send the identify message */ call phase_lock; cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; and SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; call phase_lock; cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; mov SCB_TAG jmp p_mesgout_onebyte;/* * Interrupt the driver, and allow it to send a message * if it asks. */p_mesgout_from_host: cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; mvi INTSTAT,AWAITING_MSG; nop; /* * Did the host detect a phase change? */ cmp RETURN_1, MSGOUT_PHASEMIS je p_mesgout_done;p_mesgout_onebyte: mvi CLRSINT1, CLRATNO; mov SCSIDATL, SINDEX;/* * If the next bus phase after ATN drops is a message out, it means * that the target is requesting that the last message(s) be resent. */ call phase_lock; cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ jmp p_mesgout;p_mesgout_done: mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ mov LAST_MSG, MSG_OUT; cmp MSG_OUT, MSG_IDENTIFYFLAG jne . + 2; and SCB_CONTROL, ~MK_MESSAGE; mvi MSG_OUT, MSG_NOOP; /* No message left */ jmp ITloop;/* * Message in phase. Bytes are read using Automatic PIO mode. */p_mesgin: mvi ACCUM call inb_first; /* read the 1st message byte */ test A,MSG_IDENTIFYFLAG jnz mesgin_identify; cmp A,MSG_DISCONNECT je mesgin_disconnect; cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; cmp ALLZEROS,A je mesgin_complete; cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; cmp A,MSG_EXTENDED je mesgin_extended; cmp A,MSG_MESSAGE_REJECT je mesgin_reject; cmp A,MSG_NOOP je mesgin_done;rej_mesgin:/* * We have no idea what this message in is, so we issue a message reject * and hope for the best. In any case, rejection should be a rare * occurrence - signal the driver when it happens. */ mvi INTSTAT,SEND_REJECT; /* let driver know */ mvi MSG_MESSAGE_REJECT call mk_mesg;mesgin_done: mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ jmp ITloop;mesgin_complete:/* * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO, * and trigger a completion interrupt. Before doing so, check to see if there * is a residual or the status byte is something other than STATUS_GOOD (0). * In either of these conditions, we upload the SCB back to the host so it can * process this information. In the case of a non zero status byte, we * additionally interrupt the kernel driver synchronously, allowing it to * decide if sense should be retrieved. If the kernel driver wishes to request * sense, it will fill the kernel SCB with a request sense command and set * RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE we redownload * the SCB, and process it as the next command by adding it to the waiting list. * If the kernel driver does not wish to request sense, it need only clear * RETURN_1, and the command is allowed to complete normally. We don't bother * to post to the QOUTFIFO in the error cases since it would require extra * work in the kernel driver to ensure that the entry was removed before the * command complete code tried processing it. *//* * First check for residuals */ test SCB_RESID_SGCNT,0xff jnz upload_scb; test SCB_TARGET_STATUS,0xff jz complete; /* Good Status? */upload_scb: mvi DMAPARAMS, FIFORESET; mov SCB_TAG call dma_scb;check_status: test SCB_TARGET_STATUS,0xff jz complete; /* Just a residual? */ mvi INTSTAT,BAD_STATUS; /* let driver know */ nop; cmp RETURN_1, SEND_SENSE jne complete; /* This SCB becomes the next to execute as it will retrieve sense */ mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; mov SCB_TAG call dma_scb;add_to_waiting_list: mov SCB_NEXT,WAITING_SCBH; mov WAITING_SCBH, SCBPTR; /* * Prepare our selection hardware before the busfree so we have a * high probability of winning arbitration. */ call start_selection; jmp await_busfree;complete: /* If we are untagged, clear our address up in host ram */ test SCB_CONTROL, TAG_ENB jnz complete_post; mov A, SAVED_TCL; mvi UNTAGGEDSCB_OFFSET call post_byte_setup; mvi SCB_LIST_NULL call post_byte;complete_post: /* Post the SCB and issue an interrupt */ if ((p->features & AHC_QUEUE_REGS) != 0) { mov A, SDSCB_QOFF; } else { mov A, QOUTPOS; } mvi QOUTFIFO_OFFSET call post_byte_setup; mov SCB_TAG call post_byte; if ((p->features & AHC_QUEUE_REGS) == 0) { inc QOUTPOS; } mvi INTSTAT,CMDCMPLT;add_to_free_list: call add_scb_to_free_list; jmp await_busfree;/* * Is it an extended message? Copy the message to our message buffer and * notify the host. The host will tell us whether to reject this message, * respond to it with the message that the host placed in our message buffer, * or simply to do nothing. */mesgin_extended: mvi INTSTAT,EXTENDED_MSG; /* let driver know */ jmp ITloop;/* * Is it a disconnect message? Set a flag in the SCB to remind us * and await the bus going free. */mesgin_disconnect: or SCB_CONTROL,DISCONNECTED; call add_scb_to_disc_list; jmp await_busfree;/* * Save data pointers message: * Copying RAM values back to SCB, for Save Data Pointers message, but * only if we've actually been into a data phase to change them. This * protects against bogus data in scratch ram and the residual counts * since they are only initialized when we go into data_in or data_out. */mesgin_sdptrs: test SEQ_FLAGS, DPHASE jz mesgin_done; mov SCB_SGCOUNT,SG_COUNT; /* The SCB SGPTR becomes the next one we'll download */ mvi DINDEX, SCB_SGPTR; mvi SG_NEXT call bcopy_4; /* The SCB DATAPTR0 becomes the current SHADDR */ mvi DINDEX, SCB_DATAPTR; mvi SHADDR call bcopy_4;/* * Use the residual number since STCNT is corrupted by any message transfer. */ mvi SCB_RESID_DCNT call bcopy_3; jmp mesgin_done;/* * Restore pointers message? Data pointers are recopied from the * SCB anytime we enter a data phase for the first time, so all * we need to do is clear the DPHASE flag and let the data phase * code do the rest. */mesgin_rdptrs: and SEQ_FLAGS, ~DPHASE; /* * We'll reload them * the next time through * the dataphase. */ jmp mesgin_done;/* * Identify message? For a reconnecting target, this tells us the lun * that the reconnection is for - find the correct SCB and switch to it, * clearing the "disconnected" bit so we don't "find" it by accident later. */mesgin_identify: if ((p->features & AHC_WIDE) != 0) { and A,0x0f; /* lun in lower four bits */ } else { and A,0x07; /* lun in lower three bits */ } or SAVED_TCL,A; /* SAVED_TCL should be complete now */ call get_untagged_SCBID; cmp ARG_1, SCB_LIST_NULL je snoop_tag; if ((p->flags & AHC_PAGESCBS) != 0) { test SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB; } /* * If the SCB was found in the disconnected list (as is * always the case in non-paging scenarios), SCBPTR is already * set to the correct SCB. So, simply setup the SCB and get * on with things. */ mov SCBPTR call rem_scb_from_disc_list; jmp setup_SCB;/* * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. * If we get one, we use the tag returned to find the proper * SCB. With SCB paging, this requires using search for both tagged * and non-tagged transactions since the SCB may exist in any slot. * If we're not using SCB paging, we can use the tag as the direct * index to the SCB. */snoop_tag: mov NONE,SCSIDATL; /* ACK Identify MSG */snoop_tag_loop: call phase_lock; cmp LASTPHASE, P_MESGIN jne not_found; cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;get_tag: mvi ARG_1 call inb_next; /* tag value */ if ((p->flags & AHC_PAGESCBS) == 0) {index_by_tag: mov SCBPTR,ARG_1; test SCB_CONTROL,TAG_ENB jz not_found; mov SCBPTR call rem_scb_from_disc_list; } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -