patch-2.0.36 linux/drivers/scsi/aic7xxx/aic7xxx.seq
Next file: linux/drivers/scsi/aic7xxx/sequencer.h
Previous file: linux/drivers/scsi/aic7xxx/aic7xxx.reg
Back to the patch index
Back to the overall index
- Lines: 1139
- Date:
Sun Nov 15 10:33:07 1998
- Orig file:
v2.0.35/linux/drivers/scsi/aic7xxx/aic7xxx.seq
- Orig date:
Mon Jul 13 13:46:34 1998
diff -u --recursive --new-file v2.0.35/linux/drivers/scsi/aic7xxx/aic7xxx.seq linux/drivers/scsi/aic7xxx/aic7xxx.seq
@@ -1,7 +1,7 @@
/*
* Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD.
*
- * Copyright (c) 1994-1997 Justin Gibbs.
+ * Copyright (c) 1994-1998 Justin Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -14,7 +14,7 @@
* derived from this software without specific prior written permission.
*
* Where this Software is combined with software released under the terms of
- * the GNU Public License ("GPL") and the terms of the GPL would require the
+ * the GNU Public License (GPL) and the terms of the GPL would require the
* combined work to also be released under the terms of the GPL, the terms
* and conditions of this License will apply in addition to those of the
* GPL with the exception of any terms or conditions of this License that
@@ -32,7 +32,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: aic7xxx.seq,v 1.74 1997/06/27 19:38:42 gibbs Exp $
+ * $Id: aic7xxx.seq,v 1.77 1998/06/28 02:58:57 gibbs Exp $
*/
#include "aic7xxx.reg"
@@ -59,38 +59,55 @@
reset:
clr SCSISIGO; /* De-assert BSY */
/* Always allow reselection */
-.if ( TARGET_MODE )
- mvi SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP;
-.else
- mvi SCSISEQ, ENRSELI|ENAUTOATNP;
-.endif
+ if ((p->flags & AHC_TARGETMODE) != 0) {
+ mvi SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP;
+ } else {
+ mvi SCSISEQ, ENRSELI|ENAUTOATNP;
+ }
+
+ if ((p->features & AHC_CMD_CHAN) != 0) {
+ /* Ensure that no DMA operations are in progress */
+ clr CCSGCTL;
+ clr CCSCBCTL;
+ }
+
call clear_target_state;
and SXFRCTL0, ~SPIOEN;
poll_for_work:
- mov A, QINPOS;
+ if ((p->features & AHC_QUEUE_REGS) == 0) {
+ mov A, QINPOS;
+ }
poll_for_work_loop:
- and SEQCTL, ~PAUSEDIS;
- test SSTAT0, SELDO|SELDI jnz selection;
- test SCSISEQ, ENSELO jnz poll_for_work;
-.if ( TWIN_CHANNEL )
- /*
- * Twin channel devices cannot handle things like SELTO
- * interrupts on the "background" channel. So, if we
- * are selecting, keep polling the current channel util
- * either a selection or reselection occurs.
- */
- xor SBLKCTL,SELBUSB; /* Toggle to the other bus */
+ if ((p->features & AHC_QUEUE_REGS) == 0) {
+ and SEQCTL, ~PAUSEDIS;
+ }
test SSTAT0, SELDO|SELDI jnz selection;
test SCSISEQ, ENSELO jnz poll_for_work;
- xor SBLKCTL,SELBUSB; /* Toggle back */
-.endif
+ if ((p->features & AHC_TWIN) != 0) {
+ /*
+ * Twin channel devices cannot handle things like SELTO
+ * interrupts on the "background" channel. So, if we
+ * are selecting, keep polling the current channel util
+ * either a selection or reselection occurs.
+ */
+ xor SBLKCTL,SELBUSB; /* Toggle to the other bus */
+ test SSTAT0, SELDO|SELDI jnz selection;
+ test SCSISEQ, ENSELO jnz poll_for_work;
+ xor SBLKCTL,SELBUSB; /* Toggle back */
+ }
cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
test_queue:
/* Has the driver posted any work for us? */
- or SEQCTL, PAUSEDIS;
- cmp KERNEL_QINPOS, A je poll_for_work_loop;
- inc QINPOS;
- and SEQCTL, ~PAUSEDIS;
+ if ((p->features & AHC_QUEUE_REGS) != 0) {
+ test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop;
+ mov NONE, SNSCB_QOFF;
+ inc QINPOS;
+ } else {
+ or SEQCTL, PAUSEDIS;
+ cmp KERNEL_QINPOS, A je poll_for_work_loop;
+ inc QINPOS;
+ and SEQCTL, ~PAUSEDIS;
+ }
/*
* We have at least one queued SCB now and we don't have any
@@ -98,26 +115,24 @@
* any SCBs available for use, pull the tag from the QINFIFO
* and get to work on it.
*/
-.if ( SCB_PAGING )
- mov ALLZEROS call get_free_or_disc_scb;
-.endif
+ if ((p->flags & AHC_PAGESCBS) != 0) {
+ mov ALLZEROS call get_free_or_disc_scb;
+ }
+
dequeue_scb:
add A, -1, QINPOS;
- mvi QINFIFO_OFFSET call set_SCBID_host_addr_and_cnt;
- mvi DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+ mvi QINFIFO_OFFSET call fetch_byte;
- call dma_finish;
- mov SINDEX, DFDAT;
-.if !( SCB_PAGING )
- /* In the non-paging case, the SCBID == hardware SCB index */
- mov SCBPTR, SINDEX;
-.endif
+ if ((p->flags & AHC_PAGESCBS) == 0) {
+ /* In the non-paging case, the SCBID == hardware SCB index */
+ mov SCBPTR, RETURN_2;
+ }
dma_queued_scb:
/*
* DMA the SCB from host ram into the current SCB location.
*/
mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
- call dma_scb;
+ mov RETURN_2 call dma_scb;
start_scb:
/*
@@ -135,16 +150,22 @@
jmp poll_for_work;
start_selection:
-.if ( TWIN_CHANNEL )
- and SINDEX,~SELBUSB,SBLKCTL;/* Clear the channel select bit */
- and A,SELBUSB,SCB_TCL; /* Get new channel bit */
- or SINDEX,A;
- mov SBLKCTL,SINDEX; /* select channel */
-.endif
+ if ((p->features & AHC_TWIN) != 0) {
+ and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */
+ and A,SELBUSB,SCB_TCL; /* Get new channel bit */
+ or SINDEX,A;
+ mov SBLKCTL,SINDEX; /* select channel */
+ }
initialize_scsiid:
- and A, TID, SCB_TCL; /* Get target ID */
- and SCSIID, OID; /* Clear old target */
- or SCSIID, A;
+ if ((p->features & AHC_ULTRA2) != 0) {
+ and A, TID, SCB_TCL; /* Get target ID */
+ and SCSIID_ULTRA2, OID; /* Clear old target */
+ or SCSIID_ULTRA2, A;
+ } else {
+ and A, TID, SCB_TCL; /* Get target ID */
+ and SCSIID, OID; /* Clear old target */
+ or SCSIID, A;
+ }
mvi SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret;
/*
@@ -155,143 +176,154 @@
initialize_channel:
or A, CLRSTCNT|CLRCHN, SINDEX;
or SXFRCTL0, A;
-.if ( ULTRA )
+ if ((p->features & AHC_ULTRA) != 0) {
ultra:
- mvi SINDEX, ULTRA_ENB+1;
- test SAVED_TCL, 0x80 jnz ultra_2; /* Target ID > 7 */
- dec SINDEX;
+ mvi SINDEX, ULTRA_ENB+1;
+ test SAVED_TCL, 0x80 jnz ultra_2; /* Target ID > 7 */
+ dec SINDEX;
ultra_2:
- mov FUNCTION1,SAVED_TCL;
- mov A,FUNCTION1;
- test SINDIR, A jz ndx_dtr;
- or SXFRCTL0, FAST20;
-.endif
-
+ mov FUNCTION1,SAVED_TCL;
+ mov A,FUNCTION1;
+ test SINDIR, A jz ndx_dtr;
+ or SXFRCTL0, FAST20;
+ }
/*
* Initialize SCSIRATE with the appropriate value for this target.
* The SCSIRATE settings for each target are stored in an array
- * based at TARG_SCRATCH.
+ * based at TARG_SCSIRATE.
*/
ndx_dtr:
shr A,4,SAVED_TCL;
- test SBLKCTL,SELBUSB jz ndx_dtr_2;
- or SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */
- or A,0x08; /* Channel B entries add 8 */
+ if ((p->features & AHC_TWIN) != 0) {
+ test SBLKCTL,SELBUSB jz ndx_dtr_2;
+ or SAVED_TCL, SELBUSB;
+ or A,0x08; /* Channel B entries add 8 */
ndx_dtr_2:
- add SINDEX,TARG_SCRATCH,A;
+ }
+
+ if ((p->features & AHC_ULTRA2) != 0) {
+ add SINDEX, TARG_OFFSET, A;
+ mov SCSIOFFSET, SINDIR;
+ }
+
+ add SINDEX,TARG_SCSIRATE,A;
mov SCSIRATE,SINDIR ret;
selection:
test SSTAT0,SELDO jnz select_out;
select_in:
-.if ( TARGET_MODE )
- test SSTAT0, TARGET jz initiator_reselect;
- /*
- * We've just been selected. Assert BSY and
- * setup the phase for receiving the messages
- * from the target.
- */
- mvi SCSISIGO, P_MESGOUT|BSYO;
- mvi CLRSINT0, CLRSELDO;
-
- /*
- * If ATN isn't asserted, go directly to bus free.
- */
- test SCSISIGI, ATNI jz target_busfree;
-
- /*
- * Setup the DMA for sending the identify and
- * command information.
- */
- mov A, TMODE_CMDADDR_NEXT;
- mvi TMODE_CMDADDR call set_32byte_haddr_and_clrcnt;
- mvi DFCNTRL, FIFORESET;
+ if ((p->flags & AHC_TARGETMODE) != 0) {
+ test SSTAT0, TARGET jz initiator_reselect;
+ /*
+ * We've just been selected. Assert BSY and
+ * setup the phase for receiving the messages
+ * from the target.
+ */
+ mvi SCSISIGO, P_MESGOUT|BSYO;
+ mvi CLRSINT0, CLRSELDO;
+
+ /*
+ * If ATN isn't asserted, go directly to bus free.
+ */
+ test SCSISIGI, ATNI jz target_busfree;
+
+ /*
+ * Setup the DMA for sending the identify and
+ * command information.
+ */
+ mov A, TMODE_CMDADDR_NEXT;
+ mvi DINDEX, HADDR;
+ mvi TMODE_CMDADDR call set_32byte_addr;
+ mvi DFCNTRL, FIFORESET;
- clr SINDEX;
- /* Watch ATN closely now */
+ clr SINDEX;
+ /* Watch ATN closely now */
message_loop:
- or SXFRCTL0, SPIOEN;
- test SSTAT0, SPIORDY jz .;
- and SXFRCTL0, ~SPIOEN;
- mov DINDEX, SCSIDATL;
- mov DFDAT, DINDEX;
- inc SINDEX;
-
- /* Message Testing... */
- test DINDEX, MSG_IDENTIFYFLAG jz . + 2;
- mov ARG_1, DINDEX;
-
- test SCSISIGI, ATNI jnz message_loop;
- add A, -4, SINDEX;
- jc target_cmdphase;
- mvi DFDAT, SCB_LIST_NULL; /* Terminate the message list */
+ or SXFRCTL0, SPIOEN;
+ test SSTAT0, SPIORDY jz .;
+ and SXFRCTL0, ~SPIOEN;
+ mov DINDEX, SCSIDATL;
+ mov DFDAT, DINDEX;
+ inc SINDEX;
+
+ /* Message Testing... */
+ test DINDEX, MSG_IDENTIFYFLAG jz . + 2;
+ mov ARG_1, DINDEX;
+
+ test SCSISIGI, ATNI jnz message_loop;
+ add A, -4, SINDEX;
+ jc target_cmdphase;
+ mvi DFDAT, SCB_LIST_NULL; /* Terminate the message list */
target_cmdphase:
- add HCNT[0], 1, A;
- mvi SCSISIGO, P_COMMAND|BSYO;
- or SXFRCTL0, SPIOEN;
- test SSTAT0, SPIORDY jz .;
- mov A, SCSIDATL;
- mov DFDAT, A; /* Store for host */
-
- /*
- * Determine the number of bytes to read
- * based on the command group code. Count is
- * one less than the total since we've already
- * fetched the first byte.
- */
- clr SINDEX;
- shr A, CMD_GROUP_CODE_SHIFT;
- add SEQADDR0, A;
-
- add SINDEX, CMD_GROUP0_BYTE_DELTA;
- nop; /* Group 1 and 2 are the same */
- add SINDEX, CMD_GROUP2_BYTE_DELTA;
- nop; /* Group 3 is reserved */
- add SINDEX, CMD_GROUP4_BYTE_DELTA;
- add SINDEX, CMD_GROUP5_BYTE_DELTA;
+ add HCNT[0], 1, A;
+ clr HCNT[1];
+ clr HCNT[2];
+ mvi SCSISIGO, P_COMMAND|BSYO;
+ or SXFRCTL0, SPIOEN;
+ test SSTAT0, SPIORDY jz .;
+ mov A, SCSIDATL;
+ mov DFDAT, A; /* Store for host */
+
+ /*
+ * Determine the number of bytes to read
+ * based on the command group code. Count is
+ * one less than the total since we've already
+ * fetched the first byte.
+ */
+ clr SINDEX;
+ shr A, CMD_GROUP_CODE_SHIFT;
+ add SEQADDR0, A;
+
+ add SINDEX, CMD_GROUP0_BYTE_DELTA;
+ nop; /* Group 1 and 2 are the same */
+ add SINDEX, CMD_GROUP2_BYTE_DELTA;
+ nop; /* Group 3 is reserved */
+ add SINDEX, CMD_GROUP4_BYTE_DELTA;
+ add SINDEX, CMD_GROUP5_BYTE_DELTA;
/* Group 6 and 7 are not handled yet */
- mov A, SINDEX;
- add HCNT[0], A;
+ mov A, SINDEX;
+ add HCNT[0], A;
command_loop:
- test SSTAT0, SPIORDY jz .;
- cmp SINDEX, 1 jne . + 2;
- and SXFRCTL0, ~SPIOEN; /* Last Byte */
- mov DFDAT, SCSIDATL;
- dec SINDEX;
- test SINDEX, 0xFF jnz command_loop;
+ test SSTAT0, SPIORDY jz .;
+ cmp SINDEX, 1 jne . + 2;
+ and SXFRCTL0, ~SPIOEN; /* Last Byte */
+ mov DFDAT, SCSIDATL;
+ dec SINDEX;
+ test SINDEX, 0xFF jnz command_loop;
- or DFCNTRL, HDMAEN|FIFOFLUSH;
+ or DFCNTRL, HDMAEN|FIFOFLUSH;
- call dma_finish;
+ call dma_finish;
- test ARG_1, MSG_IDENTIFY_DISCFLAG jz selectin_post;
+ test ARG_1, MSG_IDENTIFY_DISCFLAG jz selectin_post;
- mvi SCSISIGO, P_MESGIN|BSYO;
+ mvi SCSISIGO, P_MESGIN|BSYO;
- or SXFRCTL0, SPIOEN;
+ or SXFRCTL0, SPIOEN;
- mvi MSG_DISCONNECT call target_outb;
+ mvi MSG_DISCONNECT call target_outb;
selectin_post:
- inc TMODE_CMDADDR_NEXT;
- cmp TMODE_CMDADDR_NEXT, TMODE_NUMCMDS jne . + 2;
- clr TMODE_CMDADDR_NEXT;
- mvi QOUTFIFO, SCB_LIST_NULL;
- mvi INTSTAT,CMDCMPLT;
+ inc TMODE_CMDADDR_NEXT;
+ cmp TMODE_CMDADDR_NEXT, TMODE_NUMCMDS jne . + 2;
+ clr TMODE_CMDADDR_NEXT;
+ mvi QOUTFIFO, SCB_LIST_NULL;
+ mvi INTSTAT,CMDCMPLT;
- test ARG_1, MSG_IDENTIFY_DISCFLAG jnz target_busfree;
+ test ARG_1, MSG_IDENTIFY_DISCFLAG jnz target_busfree;
- /* Busy loop on something then go to data or status phase */
+ /* Busy loop on something then go to data or status phase */
target_busfree:
- clr SCSISIGO;
- jmp poll_for_work;
+ clr SCSISIGO;
+ jmp poll_for_work;
+
+ }
-.endif /* TARGET_MODE */
/*
* Reselection has been initiated by a target. Make a note that we've been
* reselected, but haven't seen an IDENTIFY message from the target yet.
@@ -396,26 +428,41 @@
jmp data_phase_loop;
p_data:
- mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
+ if ((p->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 ((p->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.
*/
- mvi DINDEX, HADDR;
- mvi SCB_DATAPTR call bcopy_7;
-
- call set_stcnt_from_hcnt;
+ if ((p->features & AHC_CMD_CHAN) != 0) {
+ bmov HADDR, SCB_DATAPTR, 7;
+ } else {
+ mvi DINDEX, HADDR;
+ mvi SCB_DATAPTR call bcopy_7;
+ }
+
+ if ((p->features & AHC_ULTRA2) == 0) {
+ call set_stcnt_from_hcnt;
+ }
mov SG_COUNT,SCB_SGCOUNT;
@@ -432,19 +479,38 @@
* had an overrun.
*/
or SXFRCTL1,BITBUCKET;
- mvi HCNT[0], 0xff;
- mvi HCNT[1], 0xff;
- mvi HCNT[2], 0xff;
- call set_stcnt_from_hcnt;
and DMAPARAMS, ~(HDMAEN|SDMAEN);
-
+ if ((p->features & AHC_ULTRA2) != 0) {
+ bmov HCNT, 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, ensure wideodd is off. */
+/* If we are the last SG block, tell the hardware. */
cmp SG_COUNT,0x01 jne data_phase_wideodd;
- and DMAPARAMS, ~WIDEODD;
+ if ((p->features & AHC_ULTRA2) != 0) {
+ or SG_CACHEPTR, LAST_SEG;
+ } else {
+ and DMAPARAMS, ~WIDEODD;
+ }
data_phase_wideodd:
- mov DMAPARAMS call dma;
+ if ((p->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;
@@ -458,11 +524,6 @@
dec SG_COUNT; /* one less segment to go */
test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */
-
- clr A; /* add sizeof(struct scatter) */
- add SG_NEXT[0],SG_SIZEOF;
- adc SG_NEXT[1],A;
-
/*
* Load a struct scatter and set up the data address and length.
* If the working value of the SG count is nonzero, then
@@ -471,33 +532,71 @@
* This, like all DMA's, assumes little-endian host data storage.
*/
sg_load:
- 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;
+ if ((p->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;
+ }
+
+ if ((p->features & AHC_ULTRA2) == 0) {
+ /* Load STCNT as well. It is a mirror of HCNT */
+ call set_stcnt_from_hcnt;
+ }
-/*
- * 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;
+/* Advance the SG pointer */
+ clr A; /* add sizeof(struct scatter) */
+ add SG_NEXT[0],SG_SIZEOF;
+ adc SG_NEXT[1],A;
-/* Load STCNT as well. It is a mirror of HCNT */
- call set_stcnt_from_hcnt;
test SSTAT1,PHASEMIS jz data_phase_loop;
+ /* Ensure the last seg is visable at the shaddow layer */
+ if ((p->features & AHC_ULTRA2) != 0) {
+ or DFCNTRL, PRELOADEN;
+ }
data_phase_finish:
+ if ((p->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
@@ -508,12 +607,17 @@
mov SCB_RESID_DCNT[2],STCNT[2];
mov SCB_RESID_SGCNT, SG_COUNT;
- /* We have seen a data phase */
- or SEQ_FLAGS, DPHASE;
+ if ((p->features & AHC_ULTRA2) != 0) {
+ or SXFRCTL0, CLRSTCNT|CLRCHN;
+ }
jmp ITloop;
data_phase_overrun:
+ if ((p->features & AHC_ULTRA2) != 0) {
+ call ultra2_dmafinish;
+ or SXFRCTL0, CLRSTCNT|CLRCHN;
+ }
/*
* Turn off BITBUCKET mode and notify the host
*/
@@ -521,6 +625,19 @@
mvi INTSTAT,DATA_OVERRUN;
jmp ITloop;
+ultra2_dmafinish:
+ if ((p->features & AHC_ULTRA2) != 0) {
+ test DFCNTRL, DIRECTION jnz ultra2_dmahalt;
+ and DFCNTRL, ~SCSIEN;
+ test DFCNTRL, SCSIEN jnz .;
+ or DFCNTRL, FIFOFLUSH;
+ test DFSTATUS, FIFOEMP jz . - 1;
+ultra2_dmahalt:
+ and DFCNTRL, ~(SCSIEN|HDMAEN);
+ test DFCNTRL, HDMAEN jnz .;
+ ret;
+ }
+
/*
* Command phase. Set up the DMA registers and let 'er rip.
*/
@@ -530,14 +647,26 @@
/*
* Load HADDR and HCNT.
*/
- mvi DINDEX, HADDR;
- mvi SCB_CMDPTR call bcopy_5;
- clr HCNT[1];
- clr HCNT[2];
-
- call set_stcnt_from_hcnt;
-
- mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma;
+ if ((p->features & AHC_ULTRA2) != 0) {
+ or SG_CACHEPTR, LAST_SEG;
+ }
+
+ if ((p->features & AHC_CMD_CHAN) != 0) {
+ bmov HADDR, SCB_CMDPTR, 5;
+ bmov HCNT[1], ALLZEROS, 2;
+ } else {
+ mvi DINDEX, HADDR;
+ mvi SCB_CMDPTR call bcopy_5;
+ clr HCNT[1];
+ clr HCNT[2];
+ }
+
+ if ((p->features & AHC_ULTRA2) == 0) {
+ call set_stcnt_from_hcnt;
+ mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma;
+ } else {
+ mvi (PRELOADEN|SCSIEN|HDMAEN|DIRECTION) call dma;
+ }
jmp ITloop;
/*
@@ -562,7 +691,6 @@
* 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).
*
@@ -574,11 +702,11 @@
mov SINDEX, MSG_OUT;
cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
p_mesgout_identify:
-.if ( WIDE )
- and SINDEX,0xf,SCB_TCL; /* lun */
-.else
- and SINDEX,0x7,SCB_TCL; /* lun */
-.endif
+ 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;
@@ -606,6 +734,7 @@
p_mesgout_from_host:
cmp SINDEX, HOST_MSG jne p_mesgout_onebyte;
mvi INTSTAT,AWAITING_MSG;
+ nop;
/*
* Did the host detect a phase change?
*/
@@ -692,6 +821,7 @@
check_status:
test SCB_TARGET_STATUS,0xff jz complete; /* Just a residual? */
mvi INTSTAT,BAD_STATUS; /* let driver know */
+ nop;
cmp RETURN_1, SEND_SENSE jne complete;
/* This SCB becomes the next to execute as it will retrieve sense */
mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
@@ -710,21 +840,21 @@
/* If we are untagged, clear our address up in host ram */
test SCB_CONTROL, TAG_ENB jnz complete_post;
mov A, SAVED_TCL;
- mvi UNTAGGEDSCB_OFFSET call set_SCBID_host_addr_and_cnt;
- mvi DFCNTRL, FIFORESET;
- mvi DFDAT, SCB_LIST_NULL;
- or DFCNTRL, HDMAEN|FIFOFLUSH;
- call dma_finish;
+ mvi UNTAGGEDSCB_OFFSET call post_byte_setup;
+ mvi SCB_LIST_NULL call post_byte;
complete_post:
/* Post the SCB and issue an interrupt */
- mov A, QOUTPOS;
- mvi QOUTFIFO_OFFSET call set_SCBID_host_addr_and_cnt;
- mvi DFCNTRL, FIFORESET;
- mov DFDAT, SCB_TAG;
- or DFCNTRL, HDMAEN|FIFOFLUSH;
- call dma_finish;
- inc QOUTPOS;
+ if ((p->features & AHC_QUEUE_REGS) != 0) {
+ mov A, SDSCB_QOFF;
+ } else {
+ mov A, QOUTPOS;
+ }
+ mvi QOUTFIFO_OFFSET call post_byte_setup;
+ mov SCB_TAG call post_byte;
+ if ((p->features & AHC_QUEUE_REGS) == 0) {
+ inc QOUTPOS;
+ }
mvi INTSTAT,CMDCMPLT;
add_to_free_list:
@@ -796,18 +926,19 @@
* clearing the "disconnected" bit so we don't "find" it by accident later.
*/
mesgin_identify:
-.if ( WIDE )
- and A,0x0f; /* lun in lower four bits */
-.else
- and A,0x07; /* lun in lower three bits */
-.endif
+
+ if ((p->features & AHC_WIDE) != 0) {
+ and A,0x0f; /* lun in lower four bits */
+ } else {
+ and A,0x07; /* lun in lower three bits */
+ }
or SAVED_TCL,A; /* SAVED_TCL should be complete now */
call get_untagged_SCBID;
cmp ARG_1, SCB_LIST_NULL je snoop_tag;
-.if ( SCB_PAGING )
- test SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB;
-.endif
+ if ((p->flags & AHC_PAGESCBS) != 0) {
+ test SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB;
+ }
/*
* If the SCB was found in the disconnected list (as is
* always the case in non-paging scenarios), SCBPTR is already
@@ -833,19 +964,19 @@
get_tag:
mvi ARG_1 call inb_next; /* tag value */
-.if ! ( SCB_PAGING )
+ if ((p->flags & AHC_PAGESCBS) == 0) {
index_by_tag:
- mov SCBPTR,ARG_1;
- test SCB_CONTROL,TAG_ENB jz not_found;
- mov SCBPTR call rem_scb_from_disc_list;
-.else
-/*
- * Ensure that the SCB the tag points to is for an SCB transaction
- * to the reconnecting target.
- */
+ mov SCBPTR,ARG_1;
+ test SCB_CONTROL,TAG_ENB jz not_found;
+ mov SCBPTR call rem_scb_from_disc_list;
+ } else {
+ /*
+ * Ensure that the SCB the tag points to is for
+ * an SCB transaction to the reconnecting target.
+ */
use_retrieveSCB:
- call retrieveSCB;
-.endif
+ call retrieveSCB;
+ }
setup_SCB:
mov A, SAVED_TCL;
cmp SCB_TCL, A jne not_found_cleanup_scb;
@@ -924,16 +1055,16 @@
inb_last:
mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/
-.if ( TARGET_MODE )
-/*
- * Send a byte to an initiator in Automatic PIO mode.
- * SPIOEN must be on prior to calling this routine.
- */
+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;
-.endif
+}
mesgin_phasemis:
/*
@@ -980,7 +1111,17 @@
dma_dmadone:
and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
dma_halt:
- test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz 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;
@@ -1079,18 +1220,67 @@
mov ARG_1, SCB_TAG ret;
mvi ARG_1, SCB_LIST_NULL ret;
-set_SCBID_host_addr_and_cnt:
- mov DINDEX, SINDEX;
- mvi SCBID_ADDR call set_1byte_haddr_and_clrcnt;
- mvi HCNT[0], 1 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 set_SCBID_host_addr_and_cnt;
- mvi DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
-
- call dma_finish;
- mov ARG_1, DFDAT ret;
+ mvi UNTAGGEDSCB_OFFSET call fetch_byte;
+ mov RETURN_1, RETURN_2 ret;
phase_lock:
test SSTAT1, REQINIT jz phase_lock;
@@ -1116,65 +1306,102 @@
mov DINDIR, SINDIR ret;
/*
- * Setup haddr and count assuming that A is an
- * index into an array of 32byte objects.
+ * 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_haddr_and_clrcnt:
- shr DINDEX, 3, A;
+set_32byte_addr:
+ shr ARG_2, 3, A;
shl A, 5;
-set_1byte_haddr_and_clrcnt: /* DINDEX must be 0 upon call */
- add HADDR[0], A, SINDIR;
- mov A, DINDEX;
- adc HADDR[1], A, SINDIR;
+/*
+ * 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 HADDR[2], A, SINDIR;
- adc HADDR[3], A, SINDIR;
- /* Clear Count */
- clr HCNT[1];
- clr HCNT[2] ret;
+ 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:
- /*
- * SCB index is in SINDEX. Determine the physical address in
- * the host where this SCB is located and load HADDR with it.
- */
mov A, SINDEX;
- mvi HSCB_ADDR call set_32byte_haddr_and_clrcnt;
- mvi HCNT[0], 28;
- mov DFCNTRL, DMAPARAMS;
- test DMAPARAMS, DIRECTION jnz dma_scb_fromhost;
- /* Fill it with the SCB data */
+ 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, 28, SINDEX;
+ 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;
- cmp SINDEX, A jne copy_scb_tofifo_loop;
- or DFCNTRL, HDMAEN|FIFOFLUSH;
+ 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;
+ 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;
+ 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;
+ 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
@@ -1188,13 +1415,13 @@
ret;
add_scb_to_free_list:
-.if ( SCB_PAGING )
- mov SCB_NEXT, FREE_SCBH;
- mov FREE_SCBH, SCBPTR;
-.endif
+ if ((p->flags & AHC_PAGESCBS) != 0) {
+ mov SCB_NEXT, FREE_SCBH;
+ mov FREE_SCBH, SCBPTR;
+ }
mvi SCB_TAG, SCB_LIST_NULL ret;
-.if ( SCB_PAGING )
+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;
@@ -1211,7 +1438,7 @@
dequeue_free_scb:
mov SCBPTR, FREE_SCBH;
mov FREE_SCBH, SCB_NEXT ret;
-.endif
+}
add_scb_to_disc_list:
/*
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov