patch-2.4.9 linux/drivers/scsi/aic7xxx/aic7xxx.seq

Next file: linux/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
Previous file: linux/drivers/scsi/aic7xxx/aic7xxx.reg
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.8/linux/drivers/scsi/aic7xxx/aic7xxx.seq linux/drivers/scsi/aic7xxx/aic7xxx.seq
@@ -28,11 +28,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: //depot/src/aic7xxx/aic7xxx.seq#27 $
- *
  * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.seq,v 1.106 2000/11/12 05:19:46 gibbs Exp $
  */
 
+VERSION = "$Id: //depot/src/aic7xxx/aic7xxx.seq#33 $"
+
 #include "aic7xxx.reg"
 #include "scsi_message.h"
 
@@ -175,16 +175,7 @@
 		 * We've just been selected.  Assert BSY and
 		 * setup the phase for receiving messages
 		 * from the target.
-		 *
-		 * If bus reset interrupts have been disabled (from a
-		 * previous reset), re-enable them now.  Resets are only
-		 * of interest when we have outstanding transactions, so
-		 * we can safely defer re-enabling the interrupt until,
-		 * as a target, we start receiving transactions again.
-		 */
-		test	SIMODE1, ENSCSIRST	jnz . + 3;
-		mvi	CLRSINT1, CLRSCSIRSTI;
-		or	SIMODE1, ENSCSIRST;
+		 */
 		mvi	SCSISIGO, P_MESGOUT|BSYO;
 
 		/*
@@ -524,7 +515,7 @@
 		mvi	MSG_DISCONNECT call target_outb;
 
 target_busfree_wait:
-		/* Wait for preceeding I/O session to complete. */
+		/* Wait for preceding I/O session to complete. */
 		test	SCSISIGI, ACKI jnz .;
 target_busfree:
 		and	SIMODE1, ~ENBUSFREE;
@@ -749,13 +740,13 @@
 	if ((ahc->features & AHC_ULTRA2) != 0) {
 		/* Does the hardware have space for another SG entry? */
 		test	DFSTATUS, PRELOAD_AVAIL jz return;
-		bmov 	HADDR, CCSGRAM, 4;
-		bmov	SINDEX, CCSGRAM, 1;
-		test	SINDEX, 0x1 jz . + 2;
+		bmov 	HADDR, CCSGRAM, 7;
+		test	HCNT[0], 0x1 jz . + 2;
 		xor	DATA_COUNT_ODD, 0x1;
-		bmov	HCNT[0], SINDEX, 1;
-		bmov	HCNT[1], CCSGRAM, 2;
 		bmov	SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1;
+		if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+			mov	SCB_RESIDUAL_DATACNT[3] call set_hhaddr;
+		}
 		call	sg_advance;
 		mov	SINDEX, SCB_RESIDUAL_SGPTR[0];
 		test	DATA_COUNT_ODD, 0x1 jz . + 2;
@@ -803,29 +794,10 @@
 	adc	HCNT[2], -1 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_ULTRA2) != 0) {
-		/*
-		 * The preload circuitry requires us to
-		 * reload the address too, so pull it from
-		 * the shaddow address.
-		 */
-		bmov	HADDR, SHADDR, 4;
-		bmov	HCNT, SCB_RESIDUAL_DATACNT, 3;
-	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
-		bmov	STCNT, SCB_RESIDUAL_DATACNT, 3;
-	} else {
-		mvi	DINDEX, STCNT;
-		mvi	SCB_RESIDUAL_DATACNT call bcopy_3;
-	}
-	and	DATA_COUNT_ODD, 0x1, SCB_RESIDUAL_DATACNT[0];
-	jmp	data_phase_loop;
-
 p_data:
+	test	SEQ_FLAGS,IDENTIFY_SEEN	jnz p_data_okay;
+	mvi	NO_IDENT jmp set_seqint;
+p_data_okay:
 	if ((ahc->features & AHC_ULTRA2) != 0) {
 		mvi	DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN;
 	} else {
@@ -833,17 +805,23 @@
 	}
 	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) {
 		/* We don't have any valid S/G elements */
 		mvi	CCSGADDR, SG_PREFETCH_CNT;
 	}
-	test	SEQ_FLAGS, DPHASE	jnz data_phase_reinit;
+	test	SEQ_FLAGS, DPHASE	jz data_phase_initialize;
+
+	/*
+	 * If we re-enter the data phase after going through another
+	 * phase, our transfer location has almost certainly been
+	 * corrupted by the interveining, non-data, transfers.  Ask
+	 * the host driver to fix us up based on the transfer residual.
+	 */
+	mvi	PDATA_REINIT	call set_seqint;
+	jmp	data_phase_loop;
 
-	/* We have seen a data phase */
+data_phase_initialize:
+	/* We have seen a data phase for the first time */
 	or	SEQ_FLAGS, DPHASE;
 
 	/*
@@ -853,6 +831,10 @@
 	 * modify the saved values in the SCB until we see a save
 	 * data pointers message.
 	 */
+	if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+		/* The lowest address byte must be loaded last. */
+		mov	SCB_DATACNT[3] call set_hhaddr;
+	}
 	if ((ahc->features & AHC_CMD_CHAN) != 0) {
 		bmov	HADDR, SCB_DATAPTR, 7;
 		bmov	SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5;
@@ -1057,6 +1039,29 @@
 ultra2_dmahalt:
 		and     DFCNTRL, ~(SCSIEN|HDMAEN);
 		test	DFCNTRL, SCSIEN|HDMAEN jnz .;
+		if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+			/*
+			 * Keep HHADDR cleared for future, 32bit addressed
+			 * only, DMA operations.
+			 *
+			 * Due to bayonette style S/G handling, our residual
+			 * data must be "fixed up" once the transfer is halted.
+			 * Here we fixup the HSHADDR stored in the high byte
+			 * of the residual data cnt.  By postponing the fixup,
+			 * we can batch the clearing of HADDR with the fixup.
+			 * If we halted on the last segment, the residual is
+			 * already correct.   If we are not on the last
+			 * segment, copy the high address directly from HSHADDR.
+			 * We don't need to worry about maintaining the
+			 * SG_LAST_SEG flag as it will always be false in the
+			 * case where an update is required.
+			 */
+			or	DSCOMMAND1, HADDLDSEL0;
+			test	SG_CACHE_SHADOW, LAST_SEG jnz . + 2;
+			mov	SCB_RESIDUAL_DATACNT[3], SHADDR;
+			clr	HADDR;
+			and	DSCOMMAND1, ~HADDLDSEL0;
+		}
 	} else {
 		/* If we are the last SG block, tell the hardware. */
 		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
@@ -1163,9 +1168,18 @@
 			call	idle_loop;
 			test	CCSGCTL, CCSGEN jnz . - 1;
 			bmov 	HADDR, CCSGRAM, 7;
-			test	CCSGRAM, SG_LAST_SEG jz . + 2;
-			or	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG;
+			/*
+			 * Workaround for flaky external SCB RAM
+			 * on certain aic7895 setups.  It seems
+			 * unable to handle direct transfers from
+			 * S/G ram to certain SCB locations.
+			 */
+			mov	SINDEX, CCSGRAM;
+			mov	SCB_RESIDUAL_DATACNT[3], SINDEX;
 		} else {
+			if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+				mov	ALLZEROS call set_hhaddr;
+			}
 			mvi	DINDEX, HADDR;
 			mvi	SCB_RESIDUAL_SGPTR	call bcopy_4;
 
@@ -1180,6 +1194,17 @@
 			mov	SCB_RESIDUAL_DATACNT[3], DFDAT;
 		}
 
+		if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+			mov	SCB_RESIDUAL_DATACNT[3] call set_hhaddr;
+
+			/*
+			 * The lowest address byte must be loaded
+			 * last as it triggers the computation of
+			 * some items in the PCI block.  The ULTRA2
+			 * chips do this on PRELOAD.
+			 */
+			mov	HADDR, HADDR;
+		}
 		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
 		  && ahc->pci_cachesize != 0) {
 			call calc_mwi_residual;
@@ -1234,6 +1259,24 @@
 		call	disable_ccsgen;
 	}
 
+	if ((ahc->features & AHC_ULTRA2) == 0) {
+		/*
+		 * Clear the high address byte so that all other DMA
+		 * operations, which use 32bit addressing, can assume
+		 * HHADDR is 0.
+		 */
+		if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+			mov	ALLZEROS call set_hhaddr;
+		}
+	}
+
+	/*
+	 * Update our residual information before the information is
+	 * lost by some other type of SCSI I/O (e.g. PIO).  If we have
+	 * transferred all data, no update is needed.
+	 *
+	 */
+	test	SCB_RESIDUAL_SGPTR, SG_LIST_NULL jnz residual_update_done;
 	if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
 	  && ahc->pci_cachesize != 0) {
 		if ((ahc->features & AHC_CMD_CHAN) != 0) {
@@ -1257,7 +1300,7 @@
 		mov	SCB_RESIDUAL_DATACNT[1], STCNT[1];
 		mov	SCB_RESIDUAL_DATACNT[2], STCNT[2];
 	}
-
+residual_update_done:
 	/*
 	 * Since we've been through a data phase, the SCB_RESID* fields
 	 * are now initialized.  Clear the full residual flag.
@@ -1289,7 +1332,9 @@
  * Command phase.  Set up the DMA registers and let 'er rip.
  */
 p_command:
-	call	assert;
+	test	SEQ_FLAGS,IDENTIFY_SEEN	jnz p_command_okay;
+	mvi	NO_IDENT jmp set_seqint;
+p_command_okay:
 
 	if ((ahc->features & AHC_ULTRA2) != 0) {
 		bmov	HCNT[0], SCB_CDB_LEN,  1;
@@ -1323,7 +1368,7 @@
 	jmp	p_command_loop;
 p_command_embedded:
 	/*
-	 * The data fifo seems to require 4 byte alligned
+	 * The data fifo seems to require 4 byte aligned
 	 * transfers from the sequencer.  Force this to
 	 * be the case by clearing HADDR[0] even though
 	 * we aren't going to touch host memeory.
@@ -1383,8 +1428,9 @@
  * and store it into the SCB.
  */
 p_status:
-	call	assert;
-
+	test	SEQ_FLAGS,IDENTIFY_SEEN	jnz p_status_okay;
+	mvi	NO_IDENT jmp set_seqint;
+p_status_okay:
 	mov	SCB_SCSI_STATUS, SCSIDATL;
 	jmp	ITloop;
 
@@ -1626,6 +1672,22 @@
 	} else {
 		test	SEQ_FLAGS, DPHASE	jz mesgin_done;
 	}
+
+	/*
+	 * If we are asked to save our position at the end of the
+	 * transfer, just mark us at the end rather than perform a
+	 * full save.
+	 */
+	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz mesgin_sdptrs_full;
+	or	SCB_SGPTR, SG_LIST_NULL;
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		jmp	ITloop;
+	} else {
+		jmp	mesgin_done;
+	}
+
+mesgin_sdptrs_full:
+
 	/*
 	 * The SCB_SGPTR becomes the next one we'll download,
 	 * and the SCB_DATAPTR becomes the current SHADDR.
@@ -1907,16 +1969,6 @@
 	and	SXFRCTL0, ~SPIOEN 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	NO_IDENT jmp set_seqint;	/* no - tell the kernel */
-
 /*
  * 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,
@@ -2157,32 +2209,21 @@
 			 * The PCI module no longer intends to perform
 			 * a PCI transaction.  Drain the fifo.
 			 */
-dma_scb_hang_empty_fifo:
-			/*
-			 * Skip lines not yet transfered into the FIFO.
-			 */
-			add	SINDEX, 7, HCNT;
-			shr	SINDEX, 3;
-
-			/*
-			 * Skip lines already copied out of the FIFO.
-			 */
-			add	A, A, SINDEX;
-
-			call	dma_scb_hang_dma_drain_fifo;
-
-			/*
-			 * Set the lines transferred to all but
-			 * those yet to reach the FIFO.
-			 */
-			not	SINDEX;
-			add	A, 5, SINDEX;
-			cmp	A, 4	je dma_finish_nowait;
+dma_scb_hang_dma_drain_fifo:
+			not	A, HCNT;
+			add	A, SCB_DOWNLOAD_SIZE+SCB_BASE+1;
+			and	A, ~0x7;
+			mov	DINDIR,DFDAT;
+			cmp	DINDEX, A jne . - 1;
+			cmp	DINDEX, SCB_DOWNLOAD_SIZE+SCB_BASE
+				je	dma_finish_nowait;
+			/* Restore A as the lines left to transfer. */
+			add	A, -SCB_BASE, DINDEX;
+			shr	A, 3;
 			jmp	dma_scb_hang_fifo;
 dma_scb_hang_dma_done:
 			and	DFCNTRL, ~HDMAEN;
 			test	DFCNTRL, HDMAEN jnz .;
-dma_scb_hang_dma_drain_fifo:
 			add	SEQADDR0, A;
 		} else {
 			call	dma_finish;
@@ -2249,6 +2290,13 @@
 	} else {
 		mvi	SCB_TAG, SCB_LIST_NULL ret;
 	}
+
+if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+set_hhaddr:
+	or	DSCOMMAND1, HADDLDSEL0;
+	and	HADDR, SG_HIGH_ADDR_BITS, SINDEX;
+	and	DSCOMMAND1, ~HADDLDSEL0 ret;
+}
 
 if ((ahc->flags & AHC_PAGESCBS) != 0) {
 get_free_or_disc_scb:

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)