📄 aic7xxx.seq
字号:
* If there is a parity error, wait for the kernel to * see the interrupt and prepare our message response * before continuing. */ test SSTAT1, REQINIT jz inb_next_wait; test SSTAT1, SCSIPERR jnz inb_next_wait; and LASTPHASE, PHASE_MASK, SCSISIGI; cmp LASTPHASE, P_MESGIN jne mesgin_phasemis;inb_first: mov DINDEX,SINDEX; mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/inb_last: mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/}if ((ahc->flags & AHC_TARGETMODE) != 0) {/* * Change to a new phase. If we are changing the state of the I/O signal, * from out to in, wait an additional data release delay before continuing. */change_phase: /* Wait for preceeding I/O session to complete. */ test SCSISIGI, ACKI jnz .; /* Change the phase */ and DINDEX, IOI, SCSISIGI; mov SCSISIGO, SINDEX; and A, IOI, SINDEX; /* * If the data direction has changed, from * out (initiator driving) to in (target driving), * we must waitat least a data release delay plus * the normal bus settle delay. [SCSI III SPI 10.11.0] */ cmp DINDEX, A je change_phase_wait; test SINDEX, IOI jz change_phase_wait; call change_phase_wait;change_phase_wait: nop; nop; nop; nop ret;/* * Send a byte to an initiator in Automatic PIO mode. */target_outb: or SXFRCTL0, SPIOEN; test SSTAT0, SPIORDY jz .; mov SCSIDATL, SINDEX; test SSTAT0, SPIORDY jz .; and SXFRCTL0, ~SPIOEN ret;} mesgin_phasemis:/* * We expected to receive another byte, but the target changed phase */ mvi INTSTAT, MSGIN_PHASEMIS; jmp ITloop;/* * DMA data transfer. HADDR and HCNT must be loaded first, and * SINDEX should contain the value to load DFCNTRL with - 0x3d for * host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared * during initialization. */dma: mov DFCNTRL,SINDEX;dma_loop: test SSTAT0,DMADONE jnz dma_dmadone; test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */dma_phasemis: test SSTAT0,SDONE jnz dma_checkfifo; mov SINDEX,ALLZEROS; /* Notify caller of phasemiss *//* * We will be "done" DMAing when the transfer count goes to zero, or * the target changes the phase (in light of this, it makes sense that * the DMA circuitry doesn't ACK when PHASEMIS is active). If we are * doing a SCSI->Host transfer, the data FIFO should be flushed auto- * magically on STCNT=0 or a phase change, so just wait for FIFO empty * status. */dma_checkfifo: test DFCNTRL,DIRECTION jnz dma_fifoempty;dma_fifoflush: test DFSTATUS,FIFOEMP jz dma_fifoflush;dma_fifoempty: /* Don't clobber an inprogress host data transfer */ test DFSTATUS, MREQPEND jnz dma_fifoempty;/* * Now shut the DMA enables off and make sure that the DMA enables are * actually off first lest we get an ILLSADDR. */dma_dmadone: and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);dma_halt: /* * Some revisions of the aic7880 have a problem where, if the * data fifo is full, but the PCI input latch is not empty, * HDMAEN cannot be cleared. The fix used here is to attempt * to drain the data fifo until there is space for the input * latch to drain and HDMAEN de-asserts. */ if ((ahc->features & AHC_ULTRA2) == 0) { mov NONE, DFDAT; } test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;return: ret;/* * Assert that if we've been reselected, then we've seen an IDENTIFY * message. */assert: test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */ mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel *//* * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL) * or by the SCBID ARG_1. The search begins at the SCB index passed in * via SINDEX which is an SCB that must be on the disconnected list. If * the SCB cannot be found, SINDEX will be SCB_LIST_NULL, otherwise, SCBPTR * is set to the proper SCB. */findSCB: mov SCBPTR,SINDEX; /* Initialize SCBPTR */ cmp ARG_1, SCB_LIST_NULL jne findSCB_by_SCBID; mov A, SAVED_TCL; mvi SCB_TCL jmp findSCB_loop; /* &SCB_TCL -> SINDEX */findSCB_by_SCBID: mov A, ARG_1; /* Tag passed in ARG_1 */ mvi SCB_TAG jmp findSCB_loop; /* &SCB_TAG -> SINDEX */findSCB_next: mov ARG_2, SCBPTR; cmp SCB_NEXT, SCB_LIST_NULL je notFound; mov SCBPTR,SCB_NEXT; dec SINDEX; /* Last comparison moved us too far */findSCB_loop: cmp SINDIR, A jne findSCB_next; mov SINDEX, SCBPTR ret;notFound: mvi SINDEX, SCB_LIST_NULL ret;/* * Retrieve an SCB by SCBID first searching the disconnected list falling * back to DMA'ing the SCB down from the host. This routine assumes that * ARG_1 is the SCBID of interrest and that SINDEX is the position in the * disconnected list to start the search from. If SINDEX is SCB_LIST_NULL, * we go directly to the host for the SCB. */retrieveSCB: test SEQ_FLAGS, SCBPTR_VALID jz retrieve_from_host; mov SCBPTR call findSCB; /* Continue the search */ cmp SINDEX, SCB_LIST_NULL je retrieve_from_host;/* * This routine expects SINDEX to contain the index of the SCB to be * removed, SCBPTR to be pointing to that SCB, and ARG_2 to be the * SCBID of the SCB just previous to this one in the list or SCB_LIST_NULL * if it is at the head. */rem_scb_from_disc_list:/* Remove this SCB from the disconnection list */ cmp ARG_2, SCB_LIST_NULL je rHead; mov DINDEX, SCB_NEXT; mov SCBPTR, ARG_2; mov SCB_NEXT, DINDEX; mov SCBPTR, SINDEX ret;rHead: mov DISCONNECTED_SCBH,SCB_NEXT ret;retrieve_from_host:/* * We didn't find it. Pull an SCB and DMA down the one we want. * We should never get here in the non-paging case. */ mov ALLZEROS call get_free_or_disc_scb; mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; /* Jump instead of call as we want to return anyway */ mov ARG_1 jmp dma_scb;/* * Determine whether a target is using tagged or non-tagged transactions * by first looking for a matching transaction based on the TCL and if * that fails, looking up this device in the host's untagged SCB array. * The TCL to search for is assumed to be in SAVED_TCL. The value is * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged). * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information * in an SCB instead of having to go to the host. */get_untagged_SCBID: cmp DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host; mvi ARG_1, SCB_LIST_NULL; mov DISCONNECTED_SCBH call findSCB; cmp SINDEX, SCB_LIST_NULL je get_SCBID_from_host; or SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */ test SCB_CONTROL, TAG_ENB jnz . + 2; mov ARG_1, SCB_TAG ret; mvi ARG_1, SCB_LIST_NULL ret;/* * Fetch a byte from host memory given an index of (A + (256 * SINDEX)) * and a base address of SCBID_ADDR. The byte is returned in RETURN_2. */fetch_byte: mov ARG_2, SINDEX; if ((ahc->features & AHC_CMD_CHAN) != 0) { mvi DINDEX, CCHADDR; mvi SCBID_ADDR call set_1byte_addr; mvi CCHCNT, 1; mvi CCSGCTL, CCSGEN|CCSGRESET; test CCSGCTL, CCSGDONE jz .; mvi CCSGCTL, CCSGRESET; bmov RETURN_2, CCSGRAM, 1 ret; } else { mvi DINDEX, HADDR; mvi SCBID_ADDR call set_1byte_addr; mvi HCNT[0], 1; clr HCNT[1]; clr HCNT[2]; mvi DFCNTRL, HDMAEN|DIRECTION|FIFORESET; call dma_finish; mov RETURN_2, DFDAT ret; }/* * Prepare the hardware to post a byte to host memory given an * index of (A + (256 * SINDEX)) and a base address of SCBID_ADDR. */post_byte_setup: mov ARG_2, SINDEX; if ((ahc->features & AHC_CMD_CHAN) != 0) { mvi DINDEX, CCHADDR; mvi SCBID_ADDR call set_1byte_addr; mvi CCHCNT, 1; mvi CCSCBCTL, CCSCBRESET ret; } else { mvi DINDEX, HADDR; mvi SCBID_ADDR call set_1byte_addr; mvi HCNT[0], 1; clr HCNT[1]; clr HCNT[2]; mvi DFCNTRL, FIFORESET ret; }post_byte: if ((ahc->features & AHC_CMD_CHAN) != 0) { bmov CCSCBRAM, SINDEX, 1; or CCSCBCTL, CCSCBEN|CCSCBRESET; test CCSCBCTL, CCSCBDONE jz .; clr CCSCBCTL ret; } else { mov DFDAT, SINDEX; or DFCNTRL, HDMAEN|FIFOFLUSH; jmp dma_finish; }get_SCBID_from_host: mov A, SAVED_TCL; mvi UNTAGGEDSCB_OFFSET call fetch_byte; mov RETURN_1, RETURN_2 ret;phase_lock: test SSTAT1, REQINIT jz phase_lock; test SSTAT1, SCSIPERR jnz phase_lock; and SCSISIGO, PHASE_MASK, SCSISIGI; and LASTPHASE, PHASE_MASK, SCSISIGI ret;if ((ahc->features & AHC_CMD_CHAN) == 0) {set_stcnt_from_hcnt: mov STCNT[0], HCNT[0]; mov STCNT[1], HCNT[1]; mov STCNT[2], HCNT[2] ret;bcopy_7: mov DINDIR, SINDIR; mov DINDIR, SINDIR;bcopy_5: mov DINDIR, SINDIR;bcopy_4: mov DINDIR, SINDIR;bcopy_3: mov DINDIR, SINDIR; mov DINDIR, SINDIR; mov DINDIR, SINDIR ret;}if ((ahc->flags & AHC_TARGETMODE) != 0) {/* * Setup addr assuming that A is an index into * an array of 32byte objects, SINDEX contains * the base address of that array, and DINDEX * contains the base address of the location * to store the indexed address. */set_32byte_addr: shr ARG_2, 3, A; shl A, 5; jmp set_1byte_addr;}/* * Setup addr assuming that A is an index into * an array of 64byte objects, SINDEX contains * the base address of that array, and DINDEX * contains the base address of the location * to store the indexed address. */set_64byte_addr: shr ARG_2, 2, A; shl A, 6;/* * Setup addr assuming that A + (ARG_1 * 256) is an * index into an array of 1byte objects, SINDEX contains * the base address of that array, and DINDEX contains * the base address of the location to store the computed * address. */set_1byte_addr: add DINDIR, A, SINDIR; mov A, ARG_2; adc DINDIR, A, SINDIR; clr A; adc DINDIR, A, SINDIR; adc DINDIR, A, SINDIR ret;/* * Either post or fetch and SCB from host memory based on the * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX. */dma_scb: mov A, SINDEX; if ((ahc->features & AHC_CMD_CHAN) != 0) { mvi DINDEX, CCHADDR; mvi HSCB_ADDR call set_64byte_addr; mov CCSCBPTR, SCBPTR; test DMAPARAMS, DIRECTION jz dma_scb_tohost; mvi CCHCNT, SCB_64BYTE_SIZE; mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET; cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; jmp dma_scb_finish;dma_scb_tohost: mvi CCHCNT, SCB_32BYTE_SIZE; if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { mvi CCSCBCTL, CCSCBRESET; bmov CCSCBRAM, SCB_CONTROL, SCB_32BYTE_SIZE; or CCSCBCTL, CCSCBEN|CCSCBRESET; test CCSCBCTL, CCSCBDONE jz .; } else { mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; }dma_scb_finish: clr CCSCBCTL; test CCSCBCTL, CCARREN|CCSCBEN jnz .; ret; } else { mvi DINDEX, HADDR; mvi HSCB_ADDR call set_64byte_addr; mvi HCNT[0], SCB_32BYTE_SIZE; clr HCNT[1]; clr HCNT[2]; mov DFCNTRL, DMAPARAMS; test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; /* Fill it with the SCB data */copy_scb_tofifo: mvi SINDEX, SCB_CONTROL; add A, SCB_32BYTE_SIZE, SINDEX;copy_scb_tofifo_loop: mov DFDAT,SINDIR; mov DFDAT,SINDIR; mov DFDAT,SINDIR; mov DFDAT,SINDIR; mov DFDAT,SINDIR; mov DFDAT,SINDIR; mov DFDAT,SINDIR; cmp SINDEX, A jne copy_scb_tofifo_loop; or DFCNTRL, HDMAEN|FIFOFLUSH;dma_scb_fromhost: call dma_finish; /* If we were putting the SCB, we are done */ test DMAPARAMS, DIRECTION jz return; mvi SCB_CONTROL call dfdat_in_7; call dfdat_in_7_continued; call dfdat_in_7_continued; jmp dfdat_in_7_continued;dfdat_in_7: mov DINDEX,SINDEX;dfdat_in_7_continued: mov DINDIR,DFDAT; mov DINDIR,DFDAT; mov DINDIR,DFDAT; mov DINDIR,DFDAT; mov DINDIR,DFDAT; mov DINDIR,DFDAT; mov DINDIR,DFDAT ret; }/* * Wait for DMA from host memory to data FIFO to complete, then disable * DMA and wait for it to acknowledge that it's off. */dma_finish: test DFSTATUS,HDONE jz dma_finish; /* Turn off DMA */ and DFCNTRL, ~HDMAEN; test DFCNTRL, HDMAEN jnz .; ret;add_scb_to_free_list: if ((ahc->flags & AHC_PAGESCBS) != 0) { mov SCB_NEXT, FREE_SCBH; mov FREE_SCBH, SCBPTR; } mvi SCB_TAG, SCB_LIST_NULL ret;if ((ahc->flags & AHC_PAGESCBS) != 0) {get_free_or_disc_scb: cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb;return_error: mvi SINDEX, SCB_LIST_NULL ret;dequeue_disc_scb: mov SCBPTR, DISCONNECTED_SCBH;dma_up_scb: mvi DMAPARAMS, FIFORESET; mov SCB_TAG call dma_scb;unlink_disc_scb: mov DISCONNECTED_SCBH, SCB_NEXT ret;dequeue_free_scb: mov SCBPTR, FREE_SCBH; mov FREE_SCBH, SCB_NEXT ret;}add_scb_to_disc_list:/* * Link this SCB into the DISCONNECTED list. This list holds the * candidates for paging out an SCB if one is needed for a new command. * Modifying the disconnected list is a critical(pause dissabled) section. */ mov SCB_NEXT, DISCONNECTED_SCBH; mov DISCONNECTED_SCBH, SCBPTR ret;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -