📄 aic7xxx.seq
字号:
/* * 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. We also reset/reallocate the FIFO to make * sure we have a clean start for the next data or command phase. */mesgin_rdptrs: and SEQ_FLAGS, ~DPHASE; /* * We'll reload them * the next time through * the dataphase. */ or SXFRCTL0, CLRSTCNT|CLRCHN; jmp mesgin_done;/* * Index into our Busy Target table. SINDEX and DINDEX are modified * upon return. SCBPTR may be modified by this action. */set_busy_target: shr DINDEX, 4, SINDEX; if ((ahc->flags & AHC_SCB_BTT) != 0) { mov SCBPTR, SAVED_LUN; add DINDEX, SCB_64_BTT; } else { add DINDEX, BUSY_TARGETS; } mov DINDIR, ARG_1 ret;/* * 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: /* * Determine whether a target is using tagged or non-tagged * transactions by first looking at the transaction stored in * the busy target array. If there is no untagged transaction * for this target or the transaction is for a different lun, then * this must be a tagged transaction. */ shr SINDEX, 4, SAVED_SCSIID; and SAVED_LUN, MSG_IDENTIFY_LUNMASK, A; if ((ahc->flags & AHC_SCB_BTT) != 0) { add SINDEX, SCB_64_BTT; mov SCBPTR, SAVED_LUN; if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { add NONE, -SCB_64_BTT, SINDEX; jc . + 2; mvi INTSTAT, OUT_OF_RANGE; nop; add NONE, -(SCB_64_BTT + 16), SINDEX; jnc . + 2; mvi INTSTAT, OUT_OF_RANGE; nop; } } else { add SINDEX, BUSY_TARGETS; if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { add NONE, -BUSY_TARGETS, SINDEX; jc . + 2; mvi INTSTAT, OUT_OF_RANGE; nop; add NONE, -(BUSY_TARGETS + 16), SINDEX; jnc . + 2; mvi INTSTAT, OUT_OF_RANGE; nop; } } mov ARG_1, SINDIR; cmp ARG_1, SCB_LIST_NULL je snoop_tag; if ((ahc->flags & AHC_PAGESCBS) != 0) { mov ARG_1 call findSCB; } else { mov SCBPTR, ARG_1; } if ((ahc->flags & AHC_SCB_BTT) != 0) { jmp setup_SCB_id_lun_okay; } else { /* * We only allow one untagged command per-target * at a time. So, if the lun doesn't match, look * for a tag message. */ and A, LID, SCB_LUN; cmp SAVED_LUN, A je setup_SCB_id_lun_okay; if ((ahc->flags & AHC_PAGESCBS) != 0) { /* * findSCB removes the SCB from the * disconnected list, so we must replace * it there should this SCB be for another * lun. */ call cleanup_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, we must search for 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: if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { or SEQ_FLAGS, 0x80; } mov NONE,SCSIDATL; /* ACK Identify MSG */ call phase_lock; if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { or SEQ_FLAGS, 0x1; } cmp LASTPHASE, P_MESGIN jne not_found; if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { or SEQ_FLAGS, 0x2; } cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;get_tag: if ((ahc->flags & AHC_PAGESCBS) != 0) { mvi ARG_1 call inb_next; /* tag value */ mov ARG_1 call findSCB; } else { mvi ARG_1 call inb_next; /* tag value */ mov SCBPTR, ARG_1; }/* * Ensure that the SCB the tag points to is for * an SCB transaction to the reconnecting target. */setup_SCB: if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { or SEQ_FLAGS, 0x4; } mov A, SCB_SCSIID; cmp SAVED_SCSIID, A jne not_found_cleanup_scb; if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { or SEQ_FLAGS, 0x8; }setup_SCB_id_okay: and A, LID, SCB_LUN; cmp SAVED_LUN, A jne not_found_cleanup_scb;setup_SCB_id_lun_okay: if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { or SEQ_FLAGS, 0x10; } test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb; and SCB_CONTROL,~DISCONNECTED; test SCB_CONTROL, TAG_ENB jnz setup_SCB_tagged; if ((ahc->flags & AHC_SCB_BTT) != 0) { mov A, SCBPTR; } mvi ARG_1, SCB_LIST_NULL; mov SAVED_SCSIID call set_busy_target; if ((ahc->flags & AHC_SCB_BTT) != 0) { mov SCBPTR, A; }setup_SCB_tagged: clr SEQ_FLAGS; /* make note of IDENTIFY */ call set_transfer_settings; /* See if the host wants to send a message upon reconnection */ test SCB_CONTROL, MK_MESSAGE jz mesgin_done; mvi HOST_MSG call mk_mesg; jmp mesgin_done;not_found_cleanup_scb: if ((ahc->flags & AHC_PAGESCBS) != 0) { call cleanup_scb; }not_found: mvi NO_MATCH call set_seqint; jmp mesgin_done;mk_mesg: if ((ahc->features & AHC_DT) == 0) { or SCSISIGO, ATNO, LASTPHASE; } else { mvi SCSISIGO, 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_wait_perr: mvi PERR_DETECTED call set_seqint; jmp inb_next_wait;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_perr;inb_next_check_phase: 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_TARGETROLE) != 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 wait at 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;} /* * Locate a disconnected SCB by SCBID. Upon return, SCBPTR and SINDEX will * be set to the position of the SCB. If the SCB cannot be found locally, * it will be paged in from host memory. RETURN_2 stores the address of the * preceding SCB in the disconnected list which can be used to speed up * removal of the found SCB from the disconnected list. */if ((ahc->flags & AHC_PAGESCBS) != 0) {BEGIN_CRITICAL;findSCB: mov A, SINDEX; /* Tag passed in SINDEX */ cmp DISCONNECTED_SCBH, SCB_LIST_NULL je findSCB_notFound; mov SCBPTR, DISCONNECTED_SCBH; /* Initialize SCBPTR */ mvi ARG_2, SCB_LIST_NULL; /* Head of list */ jmp findSCB_loop;findSCB_next: cmp SCB_NEXT, SCB_LIST_NULL je findSCB_notFound; mov ARG_2, SCBPTR; mov SCBPTR,SCB_NEXT;findSCB_loop: cmp SCB_TAG, A jne findSCB_next;rem_scb_from_disc_list: cmp ARG_2, SCB_LIST_NULL je rHead; mov DINDEX, SCB_NEXT; mov SINDEX, SCBPTR; mov SCBPTR, ARG_2; mov SCB_NEXT, DINDEX; mov SCBPTR, SINDEX ret;rHead: mov DISCONNECTED_SCBH,SCB_NEXT ret;END_CRITICAL;findSCB_notFound: /* * We didn't find it. Page in the SCB. */ mov ARG_1, A; /* Save tag */ mov ALLZEROS call get_free_or_disc_scb; mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; mov ARG_1 jmp dma_scb;}/* * Prepare the hardware to post a byte to host memory given an * index of (A + (256 * SINDEX)) and a base address of SHARED_DATA_ADDR. */post_byte_setup: mov ARG_2, SINDEX; if ((ahc->features & AHC_CMD_CHAN) != 0) { mvi DINDEX, CCHADDR; mvi SHARED_DATA_ADDR call set_1byte_addr; mvi CCHCNT, 1; mvi CCSCBCTL, CCSCBRESET ret; } else { mvi DINDEX, HADDR; mvi SHARED_DATA_ADDR call set_1byte_addr; mvi 1 call set_hcnt; 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; }phase_lock_perr: mvi PERR_DETECTED call set_seqint;phase_lock: /* * 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 phase_lock; test SSTAT1, SCSIPERR jnz phase_lock_perr;phase_lock_latch_phase: if ((ahc->features & AHC_DT) == 0) { and SCSISIGO, PHASE_MASK, SCSISIGI; } and LASTPHASE, PHASE_MASK, SCSISIGI ret;if ((ahc->features & AHC_CMD_CHAN) == 0) {set_hcnt: mov HCNT[0], SINDEX;clear_hcnt: clr HCNT[1]; clr HCNT[2] ret;set_stcnt_from_hcnt: mov STCNT[0], HCNT[0]; mov STCNT[1], HCNT[1]; mov STCNT[2], HCNT[2] ret;bcopy_8: mov DINDIR, SINDIR;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_TARGETROLE) != 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_2 * 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 an 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; if ((ahc->flags & AHC_SCB_BTT) != 0) { mvi CCHCNT, SCB_DOWNLOAD_SIZE_64; } else { mvi CCHCNT, SCB_DOWNLOAD_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_UPLOAD_SIZE; if ((ahc->features & AHC_ULTRA2) == 0) { mvi CCSCBCTL, CCSCBRESET; bmov CCSCBRAM, SCB_BASE, SCB_UPLOAD_SIZE; or CCSCBCTL, CCSCBEN|CCSCBRESET; test CCS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -