summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/aic7xxx/aic7xxx.seq
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-06-17 13:25:08 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-06-17 13:25:08 +0000
commit59223edaa18759982db0a8aced0e77457d10c68e (patch)
tree89354903b01fa0a447bffeefe00df3044495db2e /drivers/scsi/aic7xxx/aic7xxx.seq
parentdb7d4daea91e105e3859cf461d7e53b9b77454b2 (diff)
Merge with Linux 2.3.6. Sorry, this isn't tested on silicon, I don't
have a MIPS box at hand.
Diffstat (limited to 'drivers/scsi/aic7xxx/aic7xxx.seq')
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.seq1000
1 files changed, 626 insertions, 374 deletions
diff --git a/drivers/scsi/aic7xxx/aic7xxx.seq b/drivers/scsi/aic7xxx/aic7xxx.seq
index beae65cd2..4cb8e82c0 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.seq
+++ b/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-1999 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
@@ -58,39 +58,57 @@
reset:
clr SCSISIGO; /* De-assert BSY */
+ and SXFRCTL1, ~BITBUCKET;
/* 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;
+ and SXFRCTL0, ~SPIOEN;
+ 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 +116,39 @@ test_queue:
* 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;
-
- call dma_finish;
- mov SINDEX, DFDAT;
-.if !( SCB_PAGING )
- /* In the non-paging case, the SCBID == hardware SCB index */
- mov SCBPTR, SINDEX;
-.endif
+ mvi QINFIFO_OFFSET call fetch_byte;
+
+ 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;
+
+/*
+ * Preset the residual fields in case we never go through a data phase.
+ * This isn't done by the host so we can avoid a DMA to clear these
+ * fields for the normal case of I/O that completes without underrun
+ * or overrun conditions.
+ */
+ if ((p->features & AHC_CMD_CHAN) != 0) {
+ bmov SCB_RESID_DCNT, SCB_DATACNT, 3;
+ } else {
+ mov SCB_RESID_DCNT[0],SCB_DATACNT[0];
+ mov SCB_RESID_DCNT[1],SCB_DATACNT[1];
+ mov SCB_RESID_DCNT[2],SCB_DATACNT[2];
+ }
+ mov SCB_RESID_SGCNT, SCB_SGCOUNT;
start_scb:
/*
@@ -135,16 +166,22 @@ start_waiting:
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;
/*
@@ -153,145 +190,155 @@ initialize_scsiid:
* set in SXFRCTL0.
*/
initialize_channel:
- or A, CLRSTCNT|CLRCHN, SINDEX;
- or SXFRCTL0, A;
-.if ( ULTRA )
+ or SXFRCTL0, CLRSTCNT|CLRCHN, SINDEX;
+ 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;
-
- clr SINDEX;
- /* Watch ATN closely now */
+ 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 */
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;
-
- or DFCNTRL, HDMAEN|FIFOFLUSH;
+ 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;
- 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.
@@ -370,57 +417,81 @@ await_busfree:
mvi INTSTAT, BAD_PHASE;
clear_target_state:
- clr DFCNTRL; /*
- * We assume that the kernel driver
- * may reset us at any time, even
- * in the middle of a DMA, so clear
- * DFCNTRL too.
- */
- clr SCSIRATE; /*
- * We don't know the target we will
- * connect to, so default to narrow
- * transfers to avoid parity problems.
- */
- and SXFRCTL0, ~(FAST20);
+ /*
+ * 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 ((p->features & AHC_ULTRA2) != 0) {
+ bmov SCSIRATE, ALLZEROS, 2;
+ } else {
+ clr SCSIRATE;
+ and SXFRCTL0, ~(FAST20);
+ }
mvi LASTPHASE, P_BUSFREE;
/* clear target specific flags */
- and SEQ_FLAGS, (WIDE_BUS|TWIN_BUS) ret;
+ 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:
- mvi DINDEX, STCNT;
- mvi SCB_RESID_DCNT call bcopy_3;
+ if ((p->features & AHC_CMD_CHAN) != 0) {
+ if ((p->features & AHC_ULTRA2) != 0) {
+ bmov HCNT, SCB_RESID_DCNT, 3;
+ }
+ bmov STCNT, SCB_RESID_DCNT, 3;
+ } else {
+ mvi DINDEX, STCNT;
+ mvi SCB_RESID_DCNT call bcopy_3;
+ }
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;
-
- mov SG_COUNT,SCB_SGCOUNT;
-
- mvi DINDEX, SG_NEXT;
- mvi SCB_SGPTR call bcopy_4;
+ if ((p->features & AHC_CMD_CHAN) != 0) {
+ bmov HADDR, SCB_DATAPTR, 7;
+ bmov STCNT, HCNT, 3;
+ bmov SG_COUNT, SCB_SGCOUNT, 5;
+ } else {
+ mvi DINDEX, HADDR;
+ mvi SCB_DATAPTR call bcopy_7;
+ call set_stcnt_from_hcnt;
+ mvi DINDEX, SG_COUNT;
+ mvi SCB_SGCOUNT call bcopy_5;
+ }
data_phase_loop:
/* Guard against overruns */
@@ -432,19 +503,39 @@ data_phase_loop:
* 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_CMD_CHAN) != 0) {
+ if ((p->features & AHC_ULTRA2) != 0) {
+ bmov HCNT, ALLONES, 3;
+ }
+ 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, ensure wideodd is off. */
+/* If we are the last SG block, tell the hardware. */
+if ((p->features & AHC_ULTRA2) == 0) {
cmp SG_COUNT,0x01 jne data_phase_wideodd;
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 .;
+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;
+ clr SINDEX; /* Remember 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 +549,6 @@ sg_advance:
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,49 +557,95 @@ sg_advance:
* 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;
-
-/*
- * 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_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;
+ if ((p->features & AHC_ULTRA2) == 0) {
+ bmov STCNT, HCNT, 3;
+ }
+ } 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;
+ 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;
-/* Load STCNT as well. It is a mirror of HCNT */
- call set_stcnt_from_hcnt;
+ test SSTAT1, REQINIT jz .;
test SSTAT1,PHASEMIS jz data_phase_loop;
+ if ((p->features & AHC_ULTRA2) != 0) {
+ mov DFCNTRL, DMAPARAMS;
+ test SSTAT0, SDONE jnz .;
+ }
+
data_phase_finish:
/*
* 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.
*/
- 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;
-
- /* We have seen a data phase */
- or SEQ_FLAGS, DPHASE;
+ if ((p->features & AHC_ULTRA2) != 0) {
+ call ultra2_dmafinish;
+ }
+ if ((p->features & AHC_ULTRA2) == 0) {
+ if ((p->features & AHC_CMD_CHAN) != 0) {
+ bmov SCB_RESID_DCNT, STCNT, 3;
+ mov SCB_RESID_SGCNT, SG_COUNT;
+ } 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;
+ }
+ }
jmp ITloop;
data_phase_overrun:
+ if ((p->features & AHC_ULTRA2) != 0) {
+ call ultra2_dmafinish;
+ }
/*
* Turn off BITBUCKET mode and notify the host
*/
@@ -521,6 +653,22 @@ data_phase_overrun:
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 .;
+ bmov SCB_RESID_DCNT, STCNT, 3;
+ mov SCB_RESID_SGCNT, SG_COUNT;
+ or SXFRCTL0, CLRSTCNT|CLRCHN;
+ ret;
+ }
+
/*
* Command phase. Set up the DMA registers and let 'er rip.
*/
@@ -530,14 +678,33 @@ p_command:
/*
* 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_CMD_CHAN) != 0) {
+ bmov HADDR, SCB_CMDPTR, 5;
+ bmov HCNT[1], ALLZEROS, 2;
+ if ((p->features & AHC_ULTRA2) == 0) {
+ bmov STCNT, HCNT, 3;
+ }
+ } else {
+ mvi DINDEX, HADDR;
+ mvi SCB_CMDPTR call bcopy_5;
+ clr HCNT[1];
+ clr HCNT[2];
+ call set_stcnt_from_hcnt;
+ }
+
+ if ((p->features & AHC_ULTRA2) == 0) {
+ mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma;
+ } else {
+ mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION);
+ test SSTAT0, SDONE jnz .;
+p_command_dma_loop:
+ test SSTAT0, DMADONE jnz p_command_ultra2_dma_done;
+ test SSTAT1,PHASEMIS jz p_command_dma_loop; /* ie. underrun */
+p_command_ultra2_dma_done:
+ and DFCNTRL, ~(SCSIEN|HDMAEN);
+ test DFCNTRL, HDMAEN jnz .;
+ or SXFRCTL0, CLRSTCNT|CLRCHN;
+ }
jmp ITloop;
/*
@@ -562,7 +729,6 @@ p_status:
* 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).
*
@@ -570,15 +736,17 @@ p_status:
* in case the target decides to put us in this phase for some strange
* reason.
*/
+p_mesgout_retry:
+ or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
p_mesgout:
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 +774,7 @@ p_mesgout_tag:
p_mesgout_from_host:
cmp SINDEX, HOST_MSG jne p_mesgout_onebyte;
mvi INTSTAT,AWAITING_MSG;
+ nop;
/*
* Did the host detect a phase change?
*/
@@ -620,9 +789,7 @@ p_mesgout_onebyte:
* that the target is requesting that the last message(s) be resent.
*/
call phase_lock;
- cmp LASTPHASE, P_MESGOUT jne p_mesgout_done;
- or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
- jmp p_mesgout;
+ cmp LASTPHASE, P_MESGOUT je p_mesgout_retry;
p_mesgout_done:
mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */
@@ -692,6 +859,7 @@ upload_scb:
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 +878,21 @@ complete:
/* 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:
@@ -759,21 +927,23 @@ mesgin_disconnect:
*/
mesgin_sdptrs:
test SEQ_FLAGS, DPHASE jz mesgin_done;
- mov SCB_SGCOUNT,SG_COUNT;
-
- /* The SCB SGPTR becomes the next one we'll download */
- mvi DINDEX, SCB_SGPTR;
- mvi SG_NEXT call bcopy_4;
-
- /* The SCB DATAPTR0 becomes the current SHADDR */
- mvi DINDEX, SCB_DATAPTR;
- mvi SHADDR call bcopy_4;
-
-/*
- * Use the residual number since STCNT is corrupted by any message transfer.
- */
- mvi SCB_RESID_DCNT call bcopy_3;
-
+ /*
+ * The SCB SGPTR becomes the next one we'll download,
+ * and the SCB DATAPTR becomes the current SHADDR.
+ * Use the residual number since STCNT is corrupted by
+ * any message transfer.
+ */
+ if ((p->features & AHC_CMD_CHAN) != 0) {
+ bmov SCB_SGCOUNT, SG_COUNT, 5;
+ bmov SCB_DATAPTR, SHADDR, 4;
+ bmov SCB_DATACNT, SCB_RESID_DCNT, 3;
+ } else {
+ mvi DINDEX, SCB_SGCOUNT;
+ mvi SG_COUNT call bcopy_5;
+ mvi DINDEX, SCB_DATAPTR;
+ mvi SHADDR call bcopy_4;
+ mvi SCB_RESID_DCNT call bcopy_3;
+ }
jmp mesgin_done;
/*
@@ -796,18 +966,20 @@ mesgin_rdptrs:
* 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 */
+ mvi ARG_2, SCB_LIST_NULL; /* SCBID of prev SCB in disc List */
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 +1005,8 @@ snoop_tag_loop:
get_tag:
mvi ARG_1 call inb_next; /* tag value */
-.if ! ( SCB_PAGING )
-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.
- */
use_retrieveSCB:
call retrieveSCB;
-.endif
setup_SCB:
mov A, SAVED_TCL;
cmp SCB_TCL, A jne not_found_cleanup_scb;
@@ -924,16 +1085,16 @@ inb_first:
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:
/*
@@ -948,6 +1109,7 @@ mesgin_phasemis:
* host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared
* during initialization.
*/
+if ((p->features & AHC_ULTRA2) == 0) {
dma:
mov DFCNTRL,SINDEX;
dma_loop:
@@ -980,7 +1142,16 @@ dma_fifoempty:
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.
+ */
+ mov NONE, DFDAT;
+ test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
+}
return:
ret;
@@ -1009,6 +1180,7 @@ 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 */
@@ -1032,19 +1204,15 @@ retrieveSCB:
/*
* This routine expects SINDEX to contain the index of the SCB to be
- * removed and SCBPTR to be pointing to that SCB.
+ * 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 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 */
+ cmp ARG_2, SCB_LIST_NULL je rHead;
mov DINDEX, SCB_NEXT;
- mov SCBPTR, SCB_PREV;
+ mov SCBPTR, ARG_2;
mov SCB_NEXT, DINDEX;
mov SCBPTR, SINDEX ret;
rHead:
@@ -1079,25 +1247,75 @@ get_untagged_SCBID:
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;
test SSTAT1, SCSIPERR jnz phase_lock;
- and LASTPHASE, PHASE_MASK, SCSISIGI;
- mov SCSISIGO, LASTPHASE ret;
+ and SCSISIGO, PHASE_MASK, SCSISIGI;
+ and LASTPHASE, PHASE_MASK, SCSISIGI ret;
+if ((p->features & AHC_CMD_CHAN) == 0) {
set_stcnt_from_hcnt:
mov STCNT[0], HCNT[0];
mov STCNT[1], HCNT[1];
@@ -1114,87 +1332,127 @@ bcopy_3:
mov DINDIR, SINDIR;
mov DINDIR, SINDIR;
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
* DMA and wait for it to acknowledge that it's off.
*/
+if ((p->features & AHC_CMD_CHAN) == 0) {
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 ( 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;
@@ -1206,12 +1464,11 @@ 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;
+ mov DISCONNECTED_SCBH, SCB_NEXT ret;
dequeue_free_scb:
mov SCBPTR, FREE_SCBH;
mov FREE_SCBH, SCB_NEXT ret;
-.endif
+}
add_scb_to_disc_list:
/*
@@ -1219,10 +1476,5 @@ add_scb_to_disc_list:
* 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;
+ mov DISCONNECTED_SCBH, SCBPTR ret;