📄 aic7xxx.seq
字号:
mvi DINDEX, HADDR; mvi SCB_DATAPTR call bcopy_7; call set_stcnt_from_hcnt; mvi DINDEX, SG_COUNT; mvi SCB_SGCOUNT call bcopy_5; }data_phase_loop: /* Guard against overruns */ test SG_COUNT, 0xff jnz data_phase_inbounds;/* * Turn on 'Bit Bucket' mode, set the transfer count to * 16meg and let the target run until it changes phase. * When the transfer completes, notify the host that we * had an overrun. */ or SXFRCTL1,BITBUCKET; and DMAPARAMS, ~(HDMAEN|SDMAEN); if ((p->features & AHC_ULTRA2) != 0) { bmov HCNT, ALLONES, 3; } if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { bmov STCNT, ALLONES, 3; } if ((p->features & AHC_CMD_CHAN) == 0) { mvi STCNT[0], 0xFF; mvi STCNT[1], 0xFF; mvi STCNT[2], 0xFF; }data_phase_inbounds:/* If we are the last SG block, tell the hardware. */ if ((p->features & AHC_ULTRA2) != 0) { shl A, 2, SG_COUNT; cmp SG_COUNT,0x01 jne data_phase_wideodd; or A, LAST_SEG; } else { cmp SG_COUNT,0x01 jne data_phase_wideodd; and DMAPARAMS, ~WIDEODD; }data_phase_wideodd: if ((p->features & AHC_ULTRA2) != 0) { mov SG_CACHEPTR, A; mov DFCNTRL, DMAPARAMS; /* start the operation */ test SXFRCTL1, BITBUCKET jnz data_phase_overrun;u2_preload_wait: test SSTAT1, PHASEMIS jnz u2_phasemis; test DFSTATUS, PRELOAD_AVAIL jz u2_preload_wait; } 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 */sg_advance: if ((p->features & AHC_ULTRA2) != 0) { cmp SG_COUNT, 0x01 je u2_data_phase_finish; } else { dec SG_COUNT; test SG_COUNT, 0xff jz data_phase_finish; } if ((p->features & AHC_CMD_CHAN) != 0) { /* * Do we have any prefetch left??? */ cmp CCSGADDR, CCSGADDR_MAX jne prefetch_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;prefetch_avail: bmov HADDR, CCSGRAM, 8; if ((p->features & AHC_ULTRA2) == 0) { bmov STCNT, HCNT, 3; } else { dec SG_COUNT; } } 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 DINDEX, HADDR; call dfdat_in_7; 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; if ((p->features & AHC_ULTRA2) != 0) { jmp data_phase_loop; } else { test SSTAT1, REQINIT jz .; test SSTAT1,PHASEMIS jz data_phase_loop; }/* * We've loaded all of our segments into the preload layer. Now, we simply * have to wait for it to finish or for us to get a phasemis. And, since * we'll get a phasemis if we do finish, all we really need to do is wait * for a phasemis then check if we did actually complete all the segments. */ if ((p->features & AHC_ULTRA2) != 0) {u2_data_phase_finish: test SSTAT1, PHASEMIS jnz u2_phasemis; test SG_CACHEPTR, LAST_SEG_DONE jz u2_data_phase_finish; clr SG_COUNT; test SSTAT1, REQINIT jz .; test SSTAT1, PHASEMIS jz data_phase_loop;u2_phasemis: call ultra2_dmafinish; test SG_CACHEPTR, LAST_SEG_DONE jnz data_phase_finish; test SSTAT2, SHVALID jnz u2_fixup_residual; mvi INTSTAT, SEQ_SG_FIXUP; jmp data_phase_finish;u2_fixup_residual: shr ARG_1, 2, SG_CACHEPTR;u2_phasemis_loop: and A, 0x3f, SG_COUNT; cmp ARG_1, A je data_phase_finish;/* * Subtract SG_SIZEOF from the SG_NEXT pointer and add 1 to the SG_COUNT */ clr A; add SG_NEXT[0], -SG_SIZEOF; adc SG_NEXT[1], 0xff; inc SG_COUNT; jmp u2_phasemis_loop; }data_phase_finish:/* * 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. */ if ((p->features & AHC_CMD_CHAN) != 0) { bmov SCB_RESID_DCNT, STCNT, 3; mov SCB_RESID_SGCNT, SG_COUNT; if ((p->features & AHC_ULTRA2) != 0) { or SXFRCTL0, CLRSTCNT|CLRCHN; } } else { 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; } jmp ITloop;data_phase_overrun:/* * Turn off BITBUCKET mode and notify the host */ if ((p->features & AHC_ULTRA2) != 0) {/* * Wait for the target to quit transferring data on the SCSI bus */ test SSTAT1, PHASEMIS jz .; call ultra2_dmafinish; } and SXFRCTL1, ~BITBUCKET; mvi INTSTAT,DATA_OVERRUN; jmp ITloop;/* * Actually turn off the DMA hardware, save our current position into the * proper residual variables, wait for the next REQ signal, then jump to * the ITloop. Jumping to the ITloop ensures that if we happen to get * brought into the data phase again (or are still in it after our last * segment) that we will properly signal an overrun to the kernel. */ if ((p->features & AHC_ULTRA2) != 0) {ultra2_dmafinish: test DFCNTRL, DIRECTION jnz ultra2_dmahalt; and DFCNTRL, ~SCSIEN; test DFCNTRL, SCSIEN jnz .; if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) { or DFCNTRL, FIFOFLUSH; }ultra2_dmafifoflush: if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) { /* * hardware bug alert! This needless set of jumps * works around a glitch in the silicon. When the * PCI DMA fifo goes empty, but there is still SCSI * data to be flushed into the PCI DMA fifo (and from * there on into main memory), the FIFOEMP bit will * come on between the time when the PCI DMA buffer * went empty and the next bit of data is copied from * the SCSI fifo into the PCI fifo. It should only * come on when both FIFOs (meaning the entire FIFO * chain) are emtpy. Since it can take up to 4 cycles * for new data to be copied from the SCSI fifo into * the PCI fifo, testing for FIFOEMP status for 4 * extra times gives the needed time for any * remaining SCSI fifo data to be put in the PCI fifo * before we declare it *truly* empty. */ test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; } test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; test DFSTATUS, MREQPEND jnz .;ultra2_dmahalt: and DFCNTRL, ~(HDMAEN|SCSIEN); test DFCNTRL, (HDMAEN|SCSIEN) 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_CMD_CHAN) != 0) { bmov HADDR, SCB_CMDPTR, 5; bmov HCNT[1], ALLZEROS, 2; if ((p->features & AHC_ULTRA2) == 0) { bmov STCNT, HCNT, 3; } } else { mvi DINDEX, HADDR; mvi SCB_CMDPTR call bcopy_5; clr HCNT[1]; clr HCNT[2]; call set_stcnt_from_hcnt; } if ((p->features & AHC_ULTRA2) == 0) { mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma; } else { mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); test SSTAT0, SDONE jnz .;p_command_dma_loop: test SSTAT0, SDONE jnz p_command_ultra2_dma_done; test SSTAT1,PHASEMIS jz p_command_dma_loop; /* ie. underrun */p_command_ultra2_dma_done: test SCSISIGI, REQI jz p_command_ultra2_shutdown; test SSTAT1, (PHASEMIS|REQINIT) jz p_command_ultra2_dma_done;p_command_ultra2_shutdown: and DFCNTRL, ~(HDMAEN|SCSIEN); test DFCNTRL, (HDMAEN|SCSIEN) jnz .; or SXFRCTL0, CLRSTCNT|CLRCHN; } 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_retry: or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */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 je p_mesgout_retry;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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -