📄 aic7xxx.seq
字号:
/* * If we are the result of a tagged command, send * a simple Q tag and the tag id. */ test SCB_CONTROL, TAG_ENB jz . + 3; mvi MSG_SIMPLE_Q_TAG call target_outb; mov SCB_INITIATOR_TAG call target_outb; mov INITIATOR_TAG, SCB_INITIATOR_TAG;target_synccmd: /* * Now determine what phases the host wants us * to go through. */ mov SEQ_FLAGS, SCB_TARGET_PHASES; target_ITloop: /* * Start honoring ATN signals now that * we properly identified ourselves. */ test SCSISIGI, ATNI jnz target_mesgout; test SEQ_FLAGS, CMDPHASE_PENDING jnz target_cmdphase; test SEQ_FLAGS, DPHASE_PENDING jnz target_dphase; test SEQ_FLAGS, SPHASE_PENDING jnz target_sphase; /* * No more work to do. Either disconnect or not depending * on the state of NO_DISCONNECT. */ test SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; if ((ahc->flags & AHC_PAGESCBS) != 0) { mov ALLZEROS call get_free_or_disc_scb; } mov RETURN_1, ALLZEROS; call complete_target_cmd; cmp RETURN_1, CONT_MSG_LOOP jne .; mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; mov SCB_TAG call dma_scb; jmp target_synccmd;target_mesgout: mvi SCSISIGO, P_MESGOUT|BSYO; call target_inb; /* Local Processing goes here... */target_mesgout_pending_msg: jmp host_target_message_loop; target_disconnect: mvi P_MESGIN|BSYO call change_phase; test SEQ_FLAGS, DPHASE jz . + 2; mvi MSG_SAVEDATAPOINTER call target_outb; mvi MSG_DISCONNECT call target_outb;target_busfree_wait: /* Wait for preceeding I/O session to complete. */ test SCSISIGI, ACKI jnz .;target_busfree: clr SCSISIGO; call complete_target_cmd; jmp poll_for_work;target_cmdphase: mvi P_COMMAND|BSYO call change_phase; call target_inb; mov A, DINDEX; /* Store for host */ if ((ahc->features & AHC_CMD_CHAN) != 0) { mov CCSCBRAM, A; } else { mov DFDAT, A; } /* * Determine the number of bytes to read * based on the command group code via table lookup. * We reuse the first 8 bytes of the TARG_SCSIRATE * BIOS array for this table. Count is one less than * the total for the command since we've already fetched * the first byte. */ shr A, CMD_GROUP_CODE_SHIFT; add SINDEX, TARG_SCSIRATE, A; mov A, SINDIR; test A, 0xFF jz command_phase_done;command_loop: or SXFRCTL0, SPIOEN; test SSTAT0, SPIORDY jz .; cmp A, 1 jne . + 2; and SXFRCTL0, ~SPIOEN; /* Last Byte */ if ((ahc->features & AHC_CMD_CHAN) != 0) { mov CCSCBRAM, SCSIDATL; } else { mov DFDAT, SCSIDATL; } dec A; test A, 0xFF jnz command_loop;command_phase_done: and SEQ_FLAGS, ~CMDPHASE_PENDING; jmp target_ITloop;target_dphase: /* * Data direction flags are from the * perspective of the initiator. */ test SCB_TARGET_PHASES[1], TARGET_DATA_IN jz . + 4; mvi LASTPHASE, P_DATAOUT; mvi P_DATAIN|BSYO call change_phase; jmp . + 3; mvi LASTPHASE, P_DATAIN; mvi P_DATAOUT|BSYO call change_phase; mov ALLZEROS call initialize_channel; jmp p_data;target_sphase: mvi P_STATUS|BSYO call change_phase; mvi LASTPHASE, P_STATUS; mov SCB_TARGET_STATUS call target_outb; /* XXX Watch for ATN or parity errors??? */ mvi SCSISIGO, P_MESGIN|BSYO; /* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */ mov ALLZEROS call target_outb; jmp target_busfree_wait; complete_target_cmd: test SEQ_FLAGS, TARG_CMD_PENDING jnz . + 2; mov SCB_TAG jmp complete_post; if ((ahc->features & AHC_CMD_CHAN) != 0) { /* Set the valid byte */ mvi CCSCBADDR, 24; mov CCSCBRAM, ALLONES; mvi CCHCNT, 28; or CCSCBCTL, CCSCBEN|CCSCBRESET; test CCSCBCTL, CCSCBDONE jz .; clr CCSCBCTL; } else { /* Set the valid byte */ or DFCNTRL, FIFORESET; mvi DFWADDR, 3; /* Third 64bit word or byte 24 */ mov DFDAT, ALLONES; mvi HCNT[0], 28; clr HCNT[1]; clr HCNT[2]; or DFCNTRL, HDMAEN|FIFOFLUSH; call dma_finish; } inc TQINPOS; mvi INTSTAT,CMDCMPLT ret; }if ((ahc->flags & AHC_INITIATORMODE) != 0) {initiator_select: mvi SPIOEN call initialize_channel; /* * We aren't expecting a bus free, so interrupt * the kernel driver if it happens. */ mvi CLRSINT1,CLRBUSFREE; or SIMODE1, ENBUSFREE; /* * As soon as we get a successful selection, the target * should go into the message out phase since we have ATN * asserted. */ mvi MSG_OUT, MSG_IDENTIFYFLAG; or SEQ_FLAGS, IDENTIFY_SEEN; /* * Main loop for information transfer phases. Wait for the * target to assert REQ before checking MSG, C/D and I/O for * the bus phase. */ITloop: call phase_lock; mov A, LASTPHASE; test A, ~P_DATAIN jz p_data; cmp A,P_COMMAND je p_command; cmp A,P_MESGOUT je p_mesgout; cmp A,P_STATUS je p_status; cmp A,P_MESGIN je p_mesgin; mvi INTSTAT,BAD_PHASE; jmp ITloop; /* Try reading the bus again. */await_busfree: and SIMODE1, ~ENBUSFREE; mov NONE, SCSIDATL; /* Ack the last byte */ and SXFRCTL0, ~SPIOEN; test SSTAT1,REQINIT|BUSFREE jz .; test SSTAT1, BUSFREE jnz poll_for_work; mvi INTSTAT, BAD_PHASE;} clear_target_state: /* * We assume that the kernel driver may reset us * at any time, even in the middle of a DMA, so * clear DFCNTRL too. */ clr DFCNTRL; /* * We don't know the target we will connect to, * so default to narrow transfers to avoid * parity problems. */ if ((ahc->features & AHC_ULTRA2) != 0) { bmov SCSIRATE, ALLZEROS, 2; } else { clr SCSIRATE; and SXFRCTL0, ~(FAST20); } mvi LASTPHASE, P_BUSFREE; /* clear target specific flags */ clr SEQ_FLAGS ret;/* * If we re-enter the data phase after going through another phase, the * STCNT may have been cleared, so restore it from the residual field. */data_phase_reinit: if ((ahc->features & AHC_CMD_CHAN) != 0) { bmov STCNT, SCB_RESID_DCNT, 3; } else { mvi DINDEX, STCNT; mvi SCB_RESID_DCNT call bcopy_3; } and DATA_COUNT_ODD, 0x1, SCB_RESID_DCNT[0]; jmp data_phase_loop;p_data: if ((ahc->features & AHC_ULTRA2) != 0) { mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN; } else { mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; } test LASTPHASE, IOI jnz . + 2; or DMAPARAMS, DIRECTION; call assert; /* * Ensure entering a data * phase is okay - seen identify, etc. */ if ((ahc->features & AHC_CMD_CHAN) != 0) { mvi CCSGADDR, CCSGADDR_MAX; } test SEQ_FLAGS, DPHASE jnz data_phase_reinit; /* We have seen a data phase */ or SEQ_FLAGS, DPHASE; /* * Initialize the DMA address and counter from the SCB. * Also set SG_COUNT and SG_NEXT in memory since we cannot * modify the values in the SCB itself until we see a * save data pointers message. */ if ((ahc->features & AHC_CMD_CHAN) != 0) { bmov HADDR, SCB_DATAPTR, 7; } else { mvi DINDEX, HADDR; mvi SCB_DATAPTR call bcopy_7; } and DATA_COUNT_ODD, 0x1, SCB_DATACNT[0]; if ((ahc->features & AHC_ULTRA2) == 0) { if ((ahc->features & AHC_CMD_CHAN) != 0) { bmov STCNT, HCNT, 3; } else { call set_stcnt_from_hcnt; } } if ((ahc->features & AHC_CMD_CHAN) != 0) { bmov SG_COUNT, SCB_SGCOUNT, 5; } else { 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 ((ahc->features & AHC_ULTRA2) != 0) { bmov HCNT, ALLONES, 3; } else if ((ahc->features & AHC_CMD_CHAN) != 0) { bmov STCNT, ALLONES, 3; } else { 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. */ cmp SG_COUNT,0x01 jne data_phase_wideodd; if ((ahc->features & AHC_ULTRA2) != 0) { or SG_CACHEPTR, LAST_SEG; } else { and DMAPARAMS, ~WIDEODD; }data_phase_wideodd: if ((ahc->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 ((ahc->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; } /* Track odd'ness */ test HCNT[0], 0x1 jz . + 2; xor DATA_COUNT_ODD, 0x1; if ((ahc->features & AHC_ULTRA2) == 0) { /* Load STCNT as well. It is a mirror of HCNT */ if ((ahc->features & AHC_CMD_CHAN) != 0) { bmov STCNT, HCNT, 3; } else { 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 ((ahc->flags & AHC_TARGETMODE) != 0) { test SSTAT0, TARGET jnz data_phase_loop; } test SSTAT1, REQINIT jz .; test SSTAT1,PHASEMIS jz data_phase_loop; /* Ensure the last seg is visable at the shaddow layer */ if ((ahc->features & AHC_ULTRA2) != 0) { or DFCNTRL, PRELOADEN; }data_phase_finish: if ((ahc->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. */ if ((ahc->features & AHC_CMD_CHAN) != 0) { bmov SCB_RESID_DCNT, STCNT, 3; } 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; if ((ahc->features & AHC_ULTRA2) != 0) { or SXFRCTL0, CLRSTCNT|CLRCHN; } if ((ahc->flags & AHC_TARGETMODE) != 0) { test SEQ_FLAGS, DPHASE_PENDING jz ITloop; and SEQ_FLAGS, ~DPHASE_PENDING; /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -