📄 aic7xxx.seq
字号:
/* * Ensure that the SCB the tag points to is for * an SCB transaction to the reconnecting target. */use_retrieveSCB: call retrieveSCB; }setup_SCB: mov A, SAVED_TCL; cmp SCB_TCL, A jne not_found_cleanup_scb; test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb; and SCB_CONTROL,~DISCONNECTED; or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ /* See if the host wants to send a message upon reconnection */ test SCB_CONTROL, MK_MESSAGE jz mesgin_done; and SCB_CONTROL, ~MK_MESSAGE; mvi HOST_MSG call mk_mesg; jmp mesgin_done;not_found_cleanup_scb: test SCB_CONTROL, DISCONNECTED jz . + 3; call add_scb_to_disc_list; jmp not_found; call add_scb_to_free_list;not_found: mvi INTSTAT, NO_MATCH; mvi MSG_BUS_DEV_RESET call mk_mesg; jmp mesgin_done;/* * Message reject? Let the kernel driver handle this. If we have an * outstanding WDTR or SDTR negotiation, assume that it's a response from * the target selecting 8bit or asynchronous transfer, otherwise just ignore * it since we have no clue what it pertains to. */mesgin_reject: mvi INTSTAT, REJECT_MSG; jmp mesgin_done;/* * [ ADD MORE MESSAGE HANDLING HERE ] *//* * Locking the driver out, build a one-byte message passed in SINDEX * if there is no active message already. SINDEX is returned intact. */mk_mesg: or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ mov MSG_OUT,SINDEX ret;/* * Functions to read data in Automatic PIO mode. * * According to Adaptec's documentation, an ACK is not sent on input from * the target until SCSIDATL is read from. So we wait until SCSIDATL is * latched (the usual way), then read the data byte directly off the bus * using SCSIBUSL. When we have pulled the ATN line, or we just want to * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI * spec guarantees that the target will hold the data byte on the bus until * we send our ACK. * * The assumption here is that these are called in a particular sequence, * and that REQ is already set when inb_first is called. inb_{first,next} * use the same calling convention as inb. */inb_next: mov NONE,SCSIDATL; /*dummy read from latch to ACK*/inb_next_wait: /* * 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 ((p->flags & AHC_TARGETMODE) != 0) { /* * Send a byte to an initiator in Automatic PIO mode. * SPIOEN must be on prior to calling this routine. */target_outb: mov SCSIDATL, SINDEX; test SSTAT0, SPIORDY jz .; 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 ((p->features & AHC_ULTRA2) == 0) { mov NONE, DFDAT; } test DFCNTRL, 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: 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 and SCBPTR to be pointing to that SCB. */rem_scb_from_disc_list:/* Remove this SCB from the disconnection list */ cmp SCB_NEXT,SCB_LIST_NULL je unlink_prev; mov DINDEX, SCB_PREV; mov SCBPTR, SCB_NEXT; mov SCB_PREV, DINDEX; mov SCBPTR, SINDEX;unlink_prev: cmp SCB_PREV,SCB_LIST_NULL je rHead;/* At the head of the list */ mov DINDEX, SCB_NEXT; mov SCBPTR, SCB_PREV; 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 ((p->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 ((p->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 ((p->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 LASTPHASE, PHASE_MASK, SCSISIGI; mov SCSISIGO, LASTPHASE ret;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;/* * 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;/* * 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 ((p->features & AHC_CMD_CHAN) != 0) { mvi DINDEX, CCHADDR; mvi HSCB_ADDR call set_32byte_addr; mov CCSCBPTR, SCBPTR; mvi CCHCNT, 32; test DMAPARAMS, DIRECTION jz dma_scb_tohost; mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET; cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; jmp dma_scb_finish;dma_scb_tohost: if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { mvi CCSCBCTL, CCSCBRESET; bmov CCSCBRAM, SCB_CONTROL, 32; 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_32byte_addr; mvi HCNT[0], 32; 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, 32, 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; 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 ((p->flags & AHC_PAGESCBS) != 0) { mov SCB_NEXT, FREE_SCBH; mov FREE_SCBH, SCBPTR; } mvi SCB_TAG, SCB_LIST_NULL ret;if ((p->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: /* jmp instead of call since we want to return anyway */ mov SCBPTR jmp rem_scb_from_disc_list;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. */ mvi SCB_PREV, SCB_LIST_NULL; mov SCB_NEXT, DISCONNECTED_SCBH; mov DISCONNECTED_SCBH, SCBPTR; cmp SCB_NEXT,SCB_LIST_NULL je return; mov SCBPTR,SCB_NEXT; mov SCB_PREV,DISCONNECTED_SCBH; mov SCBPTR,DISCONNECTED_SCBH ret;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -