patch-2.4.11-dontuse linux/drivers/scsi/53c700.c

Next file: linux/drivers/scsi/53c700.h
Previous file: linux/drivers/scsi/53c7,8xx.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.10/linux/drivers/scsi/53c700.c linux/drivers/scsi/53c700.c
@@ -51,6 +51,19 @@
 
 /* CHANGELOG
  *
+ * Version 2.5
+ * 
+ * More Compatibility changes for 710 (now actually works).  Enhanced
+ * support for odd clock speeds which constrain SDTR negotiations.
+ * correct cacheline separation for scsi messages and status for
+ * incoherent architectures.  Use of the pci mapping functions on
+ * buffers to begin support for 64 bit drivers.
+ *
+ * Version 2.4
+ *
+ * Added support for the 53c710 chip (in 53c700 emulation mode only---no 
+ * special 53c710 instructions or registers are used).
+ *
  * Version 2.3
  *
  * More endianness/cache coherency changes.
@@ -77,7 +90,7 @@
  * Initial modularisation from the D700.  See NCR_D700.c for the rest of
  * the changelog.
  * */
-#define NCR_700_VERSION "2.3"
+#define NCR_700_VERSION "2.5"
 
 #include <linux/config.h>
 #include <linux/version.h>
@@ -98,6 +111,7 @@
 #include <asm/byteorder.h>
 #include <linux/blk.h>
 #include <linux/module.h>
+#include <linux/pci.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -105,6 +119,14 @@
 
 #include "53c700.h"
 
+/* NOTE: For 64 bit drivers there are points in the code where we use
+ * a non dereferenceable pointer to point to a structure in dma-able
+ * memory (which is 32 bits) so that we can use all of the structure
+ * operations but take the address at the end.  This macro allows us
+ * to truncate the 64 bit pointer down to 32 bits without the compiler
+ * complaining */
+#define to32bit(x)	((__u32)((unsigned long)(x)))
+
 #ifdef NCR_700_DEBUG
 #define STATIC
 #else
@@ -195,12 +217,19 @@
 NCR_700_detect(Scsi_Host_Template *tpnt,
 	       struct NCR_700_Host_Parameters *hostdata)
 {
-	__u32 *script = kmalloc(sizeof(SCRIPT), GFP_KERNEL);
-	__u32 pScript;
+	dma_addr_t pScript, pSlots;
+	__u32 *script;
 	struct Scsi_Host *host;
 	static int banner = 0;
 	int j;
 
+	/* This separation of pScript and script is not strictly
+	 * necessay, but may be useful in architectures which can
+	 * allocate consistent memory on which virt_to_bus will not
+	 * work */
+	script = kmalloc(sizeof(SCRIPT), GFP_KERNEL);
+	pScript = virt_to_bus(script);
+
 	/* Fill in the missing routines from the host template */
 	tpnt->queuecommand = NCR_700_queuecommand;
 	tpnt->eh_abort_handler = NCR_700_abort;
@@ -228,40 +257,57 @@
 		return NULL;
 	}
 
-	hostdata->slots = kmalloc(sizeof(struct NCR_700_command_slot) * NCR_700_COMMAND_SLOTS_PER_HOST, GFP_KERNEL);
-	if(hostdata->slots == NULL) {
-		printk(KERN_ERR "53c700: Failed to allocate command slots, detatching\n");
+	/* This separation of slots and pSlots may facilitate later
+	 * migration to consistent memory on architectures which
+	 * support it */
+	hostdata->slots = kmalloc(sizeof(struct NCR_700_command_slot)
+				  * NCR_700_COMMAND_SLOTS_PER_HOST,
+				  GFP_KERNEL);
+	pSlots = virt_to_bus(hostdata->slots);
+
+	hostdata->msgin = kmalloc(MSG_ARRAY_SIZE, GFP_KERNEL);
+	hostdata->msgout = kmalloc(MSG_ARRAY_SIZE, GFP_KERNEL);
+	hostdata->status = kmalloc(MSG_ARRAY_SIZE, GFP_KERNEL);
+	if(hostdata->slots == NULL || hostdata->msgin == NULL
+	   || hostdata->msgout == NULL || hostdata->status==NULL) {
+		printk(KERN_ERR "53c700: Failed to allocate command slots or message buffers, detatching\n");
 		scsi_unregister(host);
 		return NULL;
 	}
-	memset(hostdata->slots, 0, sizeof(struct NCR_700_command_slot) * NCR_700_COMMAND_SLOTS_PER_HOST);
+	memset(hostdata->slots, 0, sizeof(struct NCR_700_command_slot)
+	       * NCR_700_COMMAND_SLOTS_PER_HOST);
 	for(j = 0; j < NCR_700_COMMAND_SLOTS_PER_HOST; j++) {
+		dma_addr_t offset = (dma_addr_t)((unsigned long)&hostdata->slots[j].SG[0]
+					  - (unsigned long)&hostdata->slots[0].SG[0]);
+		hostdata->slots[j].pSG = (struct NCR_700_SG_List *)((unsigned long)(pSlots + offset));
 		if(j == 0)
 			hostdata->free_list = &hostdata->slots[j];
 		else
 			hostdata->slots[j-1].ITL_forw = &hostdata->slots[j];
 		hostdata->slots[j].state = NCR_700_SLOT_FREE;
 	}
-	host->hostdata[0] = (__u32)hostdata;
+
 	for(j = 0; j < sizeof(SCRIPT)/sizeof(SCRIPT[0]); j++) {
 		script[j] = bS_to_host(SCRIPT[j]);
 	}
-	/* bus physical address of script */
-	pScript = virt_to_bus(script);
+
 	/* adjust all labels to be bus physical */
 	for(j = 0; j < PATCHES; j++) {
 		script[LABELPATCHES[j]] = bS_to_host(pScript + SCRIPT[LABELPATCHES[j]]);
 	}
-	/* now patch up fixed addresses */
+	/* now patch up fixed addresses. 
+	 * NOTE: virt_to_bus may be wrong if consistent memory is used
+	 * for these in the future */
 	script_patch_32(script, MessageLocation,
 			virt_to_bus(&hostdata->msgout[0]));
 	script_patch_32(script, StatusAddress,
-			virt_to_bus(&hostdata->status));
+			virt_to_bus(&hostdata->status[0]));
 	script_patch_32(script, ReceiveMsgAddress,
 			virt_to_bus(&hostdata->msgin[0]));
 
 	hostdata->script = script;
 	hostdata->pScript = pScript;
+	dma_cache_wback((unsigned long)script, sizeof(SCRIPT));
 	hostdata->state = NCR_700_HOST_FREE;
 	spin_lock_init(&hostdata->lock);
 	hostdata->cmd = NULL;
@@ -272,19 +318,22 @@
 	host->hostdata[0] = (unsigned long)hostdata;
 	/* kick the chip */
 	NCR_700_writeb(0xff, host, CTEST9_REG);
-	hostdata->rev = (NCR_700_readb(host, CTEST7_REG)<<4) & 0x0f;
+	if(hostdata->chip710) 
+		hostdata->rev = (NCR_700_readb(host, CTEST8_REG)>>4) & 0x0f;
+	else
+		hostdata->rev = (NCR_700_readb(host, CTEST7_REG)>>4) & 0x0f;
 	hostdata->fast = (NCR_700_readb(host, CTEST9_REG) == 0);
 	if(banner == 0) {
 		printk(KERN_NOTICE "53c700: Version " NCR_700_VERSION " By James.Bottomley@HansenPartnership.com\n");
 		banner = 1;
 	}
 	printk(KERN_NOTICE "scsi%d: %s rev %d %s\n", host->host_no,
-	       hostdata->fast ? "53c700-66" : "53c700",
+	       hostdata->chip710 ? "53c710" : 
+	       (hostdata->fast ? "53c700-66" : "53c700"),
 	       hostdata->rev, hostdata->differential ?
 	       "(Differential)" : "");
 	/* reset the chip */
 	NCR_700_chip_reset(host);
-	NCR_700_writeb(ASYNC_OPERATION , host, SXFER_REG);
 
 	return host;
 }
@@ -295,7 +344,13 @@
 	struct NCR_700_Host_Parameters *hostdata = 
 		(struct NCR_700_Host_Parameters *)host->hostdata[0];
 
+	/* NOTE: these may be NULL if we weren't fully initialised before
+	 * the scsi_unregister was called */
 	kfree(hostdata->script);
+	kfree(hostdata->slots);
+	kfree(hostdata->msgin);
+	kfree(hostdata->msgout);
+	kfree(hostdata->status);
 	return 1;
 }
 
@@ -308,24 +363,32 @@
 }
 
 /*
- * Function : static int datapath_residual (Scsi_Host *host)
+ * Function : static int data_residual (Scsi_Host *host)
  *
  * Purpose : return residual data count of what's in the chip.  If you
  * really want to know what this function is doing, it's almost a
  * direct transcription of the algorithm described in the 53c710
  * guide, except that the DBC and DFIFO registers are only 6 bits
- * wide.
+ * wide on a 53c700.
  *
  * Inputs : host - SCSI host */
 static inline int
 NCR_700_data_residual (struct Scsi_Host *host) {
-	int count, synchronous;
+	struct NCR_700_Host_Parameters *hostdata = 
+		(struct NCR_700_Host_Parameters *)host->hostdata[0];
+	int count, synchronous = 0;
 	unsigned int ddir;
 
-	count = ((NCR_700_readb(host, DFIFO_REG) & 0x3f) -
-		 (NCR_700_readl(host, DBC_REG) & 0x3f)) & 0x3f;
+	if(hostdata->chip710) {
+		count = ((NCR_700_readb(host, DFIFO_REG) & 0x7f) -
+			 (NCR_700_readl(host, DBC_REG) & 0x7f)) & 0x7f;
+	} else {
+		count = ((NCR_700_readb(host, DFIFO_REG) & 0x3f) -
+			 (NCR_700_readl(host, DBC_REG) & 0x3f)) & 0x3f;
+	}
 	
-	synchronous = NCR_700_readb(host, SXFER_REG) & 0x0f;
+	if(hostdata->fast)
+		synchronous = NCR_700_readb(host, SXFER_REG) & 0x0f;
 	
 	/* get the data direction */
 	ddir = NCR_700_readb(host, CTEST0_REG) & 0x01;
@@ -345,6 +408,10 @@
 		if (synchronous && (sstat & SODR_REG_FULL))
 			++count;
 	}
+#ifdef NCR_700_DEBUG
+	if(count)
+		printk("RESIDUAL IS %d (ddir %d)\n", count, ddir);
+#endif
 	return count;
 }
 
@@ -530,21 +597,26 @@
 			       __u8 offset, __u8 period)
 {
 	int XFERP;
-
-	if(period*4 < NCR_700_MIN_PERIOD) {
-		printk(KERN_WARNING "53c700: Period %dns is less than SCSI-2 minimum, setting to %d\n", period*4, NCR_700_MIN_PERIOD);
-		period = NCR_700_MIN_PERIOD/4;
+	__u8 min_xferp = (hostdata->chip710
+			  ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP);
+	__u8 max_offset = (hostdata->chip710
+			   ? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET);
+	/* NOTE: NCR_700_SDTR_msg[3] contains our offer of the minimum
+	 * period.  It is set in NCR_700_chip_setup() */
+	if(period < NCR_700_SDTR_msg[3]) {
+		printk(KERN_WARNING "53c700: Period %dns is less than this chip's minimum, setting to %d\n", period*4, NCR_700_SDTR_msg[3]*4);
+		period = NCR_700_SDTR_msg[3];
 	}
 	XFERP = (period*4 * hostdata->sync_clock)/1000 - 4;
-	if(offset > NCR_700_MAX_OFFSET) {
-		printk(KERN_WARNING "53c700: Offset %d exceeds maximum, setting to %d\n",
-		       offset, NCR_700_MAX_OFFSET);
-		offset = NCR_700_MAX_OFFSET;
+	if(offset > max_offset) {
+		printk(KERN_WARNING "53c700: Offset %d exceeds chip maximum, setting to %d\n",
+		       offset, max_offset);
+		offset = max_offset;
 	}
-	if(XFERP < NCR_700_MIN_XFERP) {
+	if(XFERP < min_xferp) {
 		printk(KERN_WARNING "53c700: XFERP %d is less than minium, setting to %d\n",
-		       XFERP,  NCR_700_MIN_XFERP);
-		XFERP =  NCR_700_MIN_XFERP;
+		       XFERP,  min_xferp);
+		XFERP =  min_xferp;
 	}
 	return (offset & 0x0f) | (XFERP & 0x07)<<4;
 }
@@ -563,14 +635,28 @@
 
 		if(SCp->cmnd[0] == REQUEST_SENSE && SCp->cmnd[6] == NCR_700_INTERNAL_SENSE_MAGIC) {
 #ifdef NCR_700_DEBUG
-			printk(" ORIGINAL CMD %p RETURNED %d, new return is %d sense is",
+			printk(" ORIGINAL CMD %p RETURNED %d, new return is %d sense is\n",
 			       SCp, SCp->cmnd[7], result);
 			print_sense("53c700", SCp);
 #endif
 			if(result == 0)
 				result = SCp->cmnd[7];
 		}
-			
+
+		if(SCp->sc_data_direction != SCSI_DATA_NONE &&
+		   SCp->sc_data_direction != SCSI_DATA_UNKNOWN) {
+			int pci_direction = scsi_to_pci_dma_dir(SCp->sc_data_direction);
+			if(SCp->use_sg) {
+				pci_unmap_sg(hostdata->pci_dev, SCp->buffer,
+					     SCp->use_sg, pci_direction);
+			} else {
+				pci_unmap_single(hostdata->pci_dev,
+						 slot->dma_handle,
+						 SCp->request_bufflen,
+						 pci_direction);
+			}
+		}
+
 		free_slot(slot, hostdata);
 
 		SCp->host_scribble = NULL;
@@ -602,19 +688,47 @@
 {
 	struct NCR_700_Host_Parameters *hostdata = 
 		(struct NCR_700_Host_Parameters *)host->hostdata[0];
+	__u32 dcntl_extra = 0;
+	__u8 min_period;
+	__u8 min_xferp = (hostdata->chip710 ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP);
+
+	if(hostdata->chip710) {
+		__u8 burst_disable = hostdata->burst_disable
+			? BURST_DISABLE : 0;
+		dcntl_extra = COMPAT_700_MODE;
+
+		NCR_700_writeb(dcntl_extra, host, DCNTL_REG);
+		NCR_700_writeb(BURST_LENGTH_8  | hostdata->dmode_extra,
+			       host, DMODE_710_REG);
+		NCR_700_writeb(burst_disable | (hostdata->differential ? 
+						DIFF : 0), host, CTEST7_REG);
+		NCR_700_writeb(BTB_TIMER_DISABLE, host, CTEST0_REG);
+		NCR_700_writeb(FULL_ARBITRATION | ENABLE_PARITY | PARITY
+			       | AUTO_ATN, host, SCNTL0_REG);
+	} else {
+		NCR_700_writeb(BURST_LENGTH_8 | hostdata->dmode_extra,
+			       host, DMODE_700_REG);
+		NCR_700_writeb(hostdata->differential ? 
+			       DIFF : 0, host, CTEST7_REG);
+		if(hostdata->fast) {
+			/* this is for 700-66, does nothing on 700 */
+			NCR_700_writeb(LAST_DIS_ENBL | ENABLE_ACTIVE_NEGATION 
+				       | GENERATE_RECEIVE_PARITY, host,
+				       CTEST8_REG);
+		} else {
+			NCR_700_writeb(FULL_ARBITRATION | ENABLE_PARITY
+				       | PARITY | AUTO_ATN, host, SCNTL0_REG);
+		}
+	}
 
 	NCR_700_writeb(1 << host->this_id, host, SCID_REG);
 	NCR_700_writeb(0, host, SBCL_REG);
-	NCR_700_writeb(0, host, SXFER_REG);
+	NCR_700_writeb(ASYNC_OPERATION, host, SXFER_REG);
 
 	NCR_700_writeb(PHASE_MM_INT | SEL_TIMEOUT_INT | GROSS_ERR_INT | UX_DISC_INT
 	     | RST_INT | PAR_ERR_INT | SELECT_INT, host, SIEN_REG);
 
 	NCR_700_writeb(ABORT_INT | INT_INST_INT | ILGL_INST_INT, host, DIEN_REG);
-	NCR_700_writeb(BURST_LENGTH_8, host, DMODE_REG);
-	NCR_700_writeb(FULL_ARBITRATION | PARITY | AUTO_ATN, host, SCNTL0_REG);
-	NCR_700_writeb(LAST_DIS_ENBL | ENABLE_ACTIVE_NEGATION|GENERATE_RECEIVE_PARITY,
-	     host, CTEST8_REG);
 	NCR_700_writeb(ENABLE_SELECT, host, SCNTL1_REG);
 	if(hostdata->clock > 75) {
 		printk(KERN_ERR "53c700: Clock speed %dMHz is too high: 75Mhz is the maximum this chip can be driven at\n", hostdata->clock);
@@ -622,13 +736,13 @@
 		 * of spec: sync divider 2, async divider 3 */
 		DEBUG(("53c700: sync 2 async 3\n"));
 		NCR_700_writeb(SYNC_DIV_2_0, host, SBCL_REG);
-		NCR_700_writeb(ASYNC_DIV_3_0, host, DCNTL_REG);
+		NCR_700_writeb(ASYNC_DIV_3_0 | dcntl_extra, host, DCNTL_REG);
 		hostdata->sync_clock = hostdata->clock/2;
 	} else	if(hostdata->clock > 50  && hostdata->clock <= 75) {
 		/* sync divider 1.5, async divider 3 */
 		DEBUG(("53c700: sync 1.5 async 3\n"));
 		NCR_700_writeb(SYNC_DIV_1_5, host, SBCL_REG);
-		NCR_700_writeb(ASYNC_DIV_3_0, host, DCNTL_REG);
+		NCR_700_writeb(ASYNC_DIV_3_0 | dcntl_extra, host, DCNTL_REG);
 		hostdata->sync_clock = hostdata->clock*2;
 		hostdata->sync_clock /= 3;
 		
@@ -636,30 +750,49 @@
 		/* sync divider 1, async divider 2 */
 		DEBUG(("53c700: sync 1 async 2\n"));
 		NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
-		NCR_700_writeb(ASYNC_DIV_2_0, host, DCNTL_REG);
+		NCR_700_writeb(ASYNC_DIV_2_0 | dcntl_extra, host, DCNTL_REG);
 		hostdata->sync_clock = hostdata->clock;
 	} else if(hostdata->clock > 25 && hostdata->clock <=37) {
 		/* sync divider 1, async divider 1.5 */
 		DEBUG(("53c700: sync 1 async 1.5\n"));
 		NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
-		NCR_700_writeb(ASYNC_DIV_1_5, host, DCNTL_REG);
+		NCR_700_writeb(ASYNC_DIV_1_5 | dcntl_extra, host, DCNTL_REG);
 		hostdata->sync_clock = hostdata->clock;
 	} else {
 		DEBUG(("53c700: sync 1 async 1\n"));
 		NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
-		NCR_700_writeb(ASYNC_DIV_1_0, host, DCNTL_REG);
+		NCR_700_writeb(ASYNC_DIV_1_0 | dcntl_extra, host, DCNTL_REG);
 		/* sync divider 1, async divider 1 */
+		hostdata->sync_clock = hostdata->clock;
+	}
+	/* Calculate the actual minimum period that can be supported
+	 * by our synchronous clock speed.  See the 710 manual for
+	 * exact details of this calculation which is based on a
+	 * setting of the SXFER register */
+	min_period = 1000*(4+min_xferp)/(4*hostdata->sync_clock);
+	if(min_period > NCR_700_MIN_PERIOD) {
+		NCR_700_SDTR_msg[3] = min_period;
 	}
+	if(hostdata->chip710)
+		NCR_700_SDTR_msg[4] = NCR_710_MAX_OFFSET;
 }
 
 STATIC void
 NCR_700_chip_reset(struct Scsi_Host *host)
 {
-	/* Chip reset */
-	NCR_700_writeb(SOFTWARE_RESET, host, DCNTL_REG);
-	udelay(100);
+	struct NCR_700_Host_Parameters *hostdata = 
+		(struct NCR_700_Host_Parameters *)host->hostdata[0];
+	if(hostdata->chip710) {
+		NCR_700_writeb(SOFTWARE_RESET_710, host, ISTAT_REG);
+		udelay(100);
 
-	NCR_700_writeb(0, host, DCNTL_REG);
+		NCR_700_writeb(0, host, ISTAT_REG);
+	} else {
+		NCR_700_writeb(SOFTWARE_RESET, host, DCNTL_REG);
+		udelay(100);
+		
+		NCR_700_writeb(0, host, DCNTL_REG);
+	}
 
 	mdelay(1000);
 
@@ -717,7 +850,7 @@
 			printk(KERN_WARNING "scsi%d Unexpected SDTR msg\n",
 			       host->host_no);
 			hostdata->msgout[0] = A_REJECT_MSG;
-			dma_cache_wback((unsigned long)hostdata->msgout, sizeof(hostdata->msgout));
+			dma_cache_wback((unsigned long)hostdata->msgout, 1);
 			script_patch_16(hostdata->script, MessageCount, 1);
 			/* SendMsgOut returns, so set up the return
 			 * address */
@@ -729,7 +862,7 @@
 		printk(KERN_INFO "scsi%d: (%d:%d), Unsolicited WDTR after CMD, Rejecting\n",
 		       host->host_no, pun, lun);
 		hostdata->msgout[0] = A_REJECT_MSG;
-		dma_cache_wback((unsigned long)hostdata->msgout, sizeof(hostdata->msgout));
+		dma_cache_wback((unsigned long)hostdata->msgout, 1);
 		script_patch_16(hostdata->script, MessageCount, 1);
 		resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
 
@@ -743,7 +876,7 @@
 		printk("\n");
 		/* just reject it */
 		hostdata->msgout[0] = A_REJECT_MSG;
-		dma_cache_wback((unsigned long)hostdata->msgout, sizeof(hostdata->msgout));
+		dma_cache_wback((unsigned long)hostdata->msgout, 1);
 		script_patch_16(hostdata->script, MessageCount, 1);
 		/* SendMsgOut returns, so set up the return
 		 * address */
@@ -761,8 +894,6 @@
 	__u32 temp = dsp + 8, resume_offset = dsp;
 	__u8 pun = 0xff, lun = 0xff;
 
-	dma_cache_inv((unsigned long)hostdata->msgin, sizeof(hostdata->msgin));
-
 	if(SCp != NULL) {
 		pun = SCp->target;
 		lun = SCp->lun;
@@ -778,8 +909,9 @@
 	switch(hostdata->msgin[0]) {
 
 	case A_EXTENDED_MSG:
-		return process_extended_message(host, hostdata, SCp,
-						dsp, dsps);
+		resume_offset =  process_extended_message(host, hostdata, SCp,
+							  dsp, dsps);
+		break;
 
 	case A_REJECT_MSG:
 		if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) {
@@ -792,6 +924,8 @@
 			printk(KERN_WARNING "scsi%d (%d:%d) Rejected first tag queue attempt, turning off tag queueing\n", host->host_no, pun, lun);
 			NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
 			hostdata->tag_negotiated &= ~(1<<SCp->target);
+			SCp->device->tagged_queue = 0;
+			SCp->device->tagged_supported = 0;
 		} else {
 			printk(KERN_WARNING "scsi%d (%d:%d) Unexpected REJECT Message %s\n",
 			       host->host_no, pun, lun,
@@ -820,7 +954,7 @@
 		printk("\n");
 		/* just reject it */
 		hostdata->msgout[0] = A_REJECT_MSG;
-		dma_cache_wback((unsigned long)hostdata->msgout, sizeof(hostdata->msgout));
+		dma_cache_wback((unsigned long)hostdata->msgout, 1);
 		script_patch_16(hostdata->script, MessageCount, 1);
 		/* SendMsgOut returns, so set up the return
 		 * address */
@@ -829,6 +963,8 @@
 		break;
 	}
 	NCR_700_writel(temp, host, TEMP_REG);
+	/* set us up to receive another message */
+	dma_cache_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE);
 	return resume_offset;
 }
 
@@ -846,25 +982,26 @@
 	}
 
 	if(dsps == A_GOOD_STATUS_AFTER_STATUS) {
-		dma_cache_inv((unsigned long)hostdata->status, sizeof(hostdata->status));
 		DEBUG(("  COMMAND COMPLETE, status=%02x\n",
-		       hostdata->status));
+		       hostdata->status[0]));
 		/* OK, if TCQ still on, we know it works */
 		NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
 		/* check for contingent allegiance contitions */
-		if(status_byte(hostdata->status) == CHECK_CONDITION ||
-		   status_byte(hostdata->status) == COMMAND_TERMINATED) {
+		if(status_byte(hostdata->status[0]) == CHECK_CONDITION ||
+		   status_byte(hostdata->status[0]) == COMMAND_TERMINATED) {
 			struct NCR_700_command_slot *slot =
 				(struct NCR_700_command_slot *)SCp->host_scribble;
 			if(SCp->cmnd[0] == REQUEST_SENSE) {
 				/* OOPS: bad device, returning another
 				 * contingent allegiance condition */
 				printk(KERN_ERR "scsi%d (%d:%d) broken device is looping in contingent allegiance: ignoring\n", host->host_no, pun, lun);
-				NCR_700_scsi_done(hostdata, SCp, hostdata->status);
+				NCR_700_scsi_done(hostdata, SCp, hostdata->status[0]);
 			} else {
-
-				DEBUG(("  cmd %p has status %d, requesting sense\n",
-				       SCp, hostdata->status));
+#ifdef NCR_DEBUG
+				print_command(SCp->cmnd);
+				printk("  cmd %p has status %d, requesting sense\n",
+				       SCp, hostdata->status[0]);
+#endif
 				/* we can destroy the command here because the
 				 * contingent allegiance condition will cause a 
 				 * retry which will re-copy the command from the
@@ -881,7 +1018,9 @@
 				 * was an internal sense request and the original
 				 * status at the end of the command */
 				SCp->cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC;
-				SCp->cmnd[7] = hostdata->status;
+				SCp->cmnd[7] = hostdata->status[0];
+				SCp->sc_data_direction = SCSI_DATA_READ;
+				dma_cache_wback((unsigned long)SCp->cmnd, SCp->cmd_len);
 				slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer));
 				slot->SG[0].pAddr = bS_to_host(virt_to_bus(SCp->sense_buffer));
 				slot->SG[1].ins = bS_to_host(SCRIPT_RETURN);
@@ -896,20 +1035,27 @@
 				hostdata->cmd = NULL;
 			}
 		} else {
-			if(status_byte(hostdata->status) == GOOD &&
-			   SCp->cmnd[0] == INQUIRY && SCp->use_sg == 0) {
-				/* Piggy back the tag queueing support
-				 * on this command */
-				if(((char *)SCp->request_buffer)[7] & 0x02) {
-					printk(KERN_INFO "scsi%d: (%d:%d) Enabling Tag Command Queuing\n", host->host_no, pun, lun);
-					hostdata->tag_negotiated |= (1<<SCp->target);
-					NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
-				} else {
-					NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
-					hostdata->tag_negotiated &= ~(1<<SCp->target);
-				}
-			}
-			NCR_700_scsi_done(hostdata, SCp, hostdata->status);
+			// Currently rely on the mid layer evaluation
+			// of the tag queuing capability
+			//
+			//if(status_byte(hostdata->status[0]) == GOOD &&
+			//   SCp->cmnd[0] == INQUIRY && SCp->use_sg == 0) {
+			//	/* Piggy back the tag queueing support
+			//	 * on this command */
+			//	pci_dma_sync_single(hostdata->pci_dev,
+			//			    slot->dma_handle,
+			//			    SCp->request_bufflen,
+			//			    PCI_DMA_FROMDEVICE);
+			//	if(((char *)SCp->request_buffer)[7] & 0x02) {
+			//		printk(KERN_INFO "scsi%d: (%d:%d) Enabling Tag Command Queuing\n", host->host_no, pun, lun);
+			//		hostdata->tag_negotiated |= (1<<SCp->target);
+			//		NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
+			//	} else {
+			//		NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
+			//		hostdata->tag_negotiated &= ~(1<<SCp->target);
+			//	}
+			//}
+			NCR_700_scsi_done(hostdata, SCp, hostdata->status[0]);
 		}
 	} else if((dsps & 0xfffff0f0) == A_UNEXPECTED_PHASE) {
 		__u8 i = (dsps & 0xf00) >> 8;
@@ -947,8 +1093,6 @@
 		struct NCR_700_command_slot *slot;
 		__u8 reselection_id = hostdata->reselection_id;
 
-		dma_cache_inv((unsigned long)hostdata->msgin, sizeof(hostdata->msgin));
-
 		lun = hostdata->msgin[0] & 0x1f;
 
 		hostdata->reselection_id = 0xff;
@@ -996,7 +1140,7 @@
 			script_patch_16(hostdata->script,
 					CommandCount, slot->cmnd->cmd_len);
 			script_patch_32_abs(hostdata->script, SGScriptStartAddress,
-					    virt_to_bus(&slot->SG[0].ins));
+					    to32bit(&slot->pSG[0].ins));
 
 			/* Note: setting SXFER only works if we're
 			 * still in the MESSAGE phase, so it is vital
@@ -1005,6 +1149,16 @@
 			 * should therefore always clear ACK */
 			NCR_700_writeb(NCR_700_get_SXFER(hostdata->cmd->device),
 				       host, SXFER_REG);
+			dma_cache_inv((unsigned long)hostdata->msgin,
+				      MSG_ARRAY_SIZE);
+			dma_cache_wback((unsigned long)hostdata->msgout,
+					MSG_ARRAY_SIZE);
+			/* I'm just being paranoid here, the command should
+			 * already have been flushed from the cache */
+			dma_cache_wback((unsigned long)slot->cmnd->cmnd,
+					slot->cmnd->cmd_len);
+
+
 			
 		}
 	} else if(dsps == A_RESELECTED_DURING_SELECTION) {
@@ -1022,20 +1176,22 @@
 		/* Take out our own ID */
 		reselection_id &= ~(1<<host->this_id);
 		
-		printk(KERN_INFO "scsi%d: (%d:%d) RESELECTION DURING SELECTION, dsp=%p[%04x] state=%d, count=%d\n",
-		       host->host_no, reselection_id, lun, (void *)dsp, dsp - hostdata->pScript, hostdata->state, hostdata->command_slot_count);
+		/* I've never seen this happen, so keep this as a printk rather
+		 * than a debug */
+		printk(KERN_INFO "scsi%d: (%d:%d) RESELECTION DURING SELECTION, dsp=%08x[%04x] state=%d, count=%d\n",
+		       host->host_no, reselection_id, lun, dsp, dsp - hostdata->pScript, hostdata->state, hostdata->command_slot_count);
 
 		{
 			/* FIXME: DEBUGGING CODE */
-			__u32 SG = (__u32)bus_to_virt(hostdata->script[A_SGScriptStartAddress_used[0]]);
+			__u32 SG = (__u32)bS_to_cpu(hostdata->script[A_SGScriptStartAddress_used[0]]);
 			int i;
 
 			for(i=0; i< NCR_700_COMMAND_SLOTS_PER_HOST; i++) {
-				if(SG >= (__u32)(&hostdata->slots[i].SG[0])
-				   && SG <= (__u32)(&hostdata->slots[i].SG[NCR_700_SG_SEGMENTS]))
+				if(SG >= to32bit(&hostdata->slots[i].pSG[0])
+				   && SG <= to32bit(&hostdata->slots[i].pSG[NCR_700_SG_SEGMENTS]))
 					break;
 			}
-			printk(KERN_INFO "IDENTIFIED SG segment as being %p in slot %p, cmd %p, slot->resume_offset=%p\n", (void *)SG, &hostdata->slots[i], hostdata->slots[i].cmnd, (void *)hostdata->slots[i].resume_offset);
+			printk(KERN_INFO "IDENTIFIED SG segment as being %08x in slot %p, cmd %p, slot->resume_offset=%08x\n", SG, &hostdata->slots[i], hostdata->slots[i].cmnd, hostdata->slots[i].resume_offset);
 			SCp =  hostdata->slots[i].cmnd;
 		}
 
@@ -1061,8 +1217,9 @@
 			reselection_id = bitmap_to_number(reselection_id);
 		}
 		hostdata->reselection_id = reselection_id;
+		/* just in case we have a stale simple tag message, clear it */
 		hostdata->msgin[1] = 0;
-		dma_cache_wback((unsigned long)hostdata->msgin, sizeof(hostdata->msgin));
+		dma_cache_wback_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE);
 		if(hostdata->tag_negotiated & (1<<reselection_id)) {
 			resume_offset = hostdata->pScript + Ent_GetReselectionWithTag;
 		} else {
@@ -1092,8 +1249,8 @@
 		}	       
 		NCR_700_internal_bus_reset(host);
 	} else if((dsps & 0xfffff000) == A_DEBUG_INTERRUPT) {
-		printk(KERN_NOTICE "scsi%d (%d:%d) DEBUG INTERRUPT %d AT %p[%04x], continuing\n",
-		       host->host_no, pun, lun, dsps & 0xfff, (void *)dsp, dsp - hostdata->pScript);
+		printk(KERN_NOTICE "scsi%d (%d:%d) DEBUG INTERRUPT %d AT %08x[%04x], continuing\n",
+		       host->host_no, pun, lun, dsps & 0xfff, dsp, dsp - hostdata->pScript);
 		resume_offset = dsp;
 	} else {
 		printk(KERN_ERR "scsi%d: (%d:%d), unidentified script interrupt 0x%x at %04x\n",
@@ -1122,7 +1279,8 @@
 	__u8 sbcl;
 
 	for(count = 0; count < 5; count++) {
-		id = NCR_700_readb(host, SFBR_REG);
+		id = NCR_700_readb(host, hostdata->chip710 ?
+				   CTEST9_REG : SFBR_REG);
 
 		/* Take out our own ID */
 		id &= ~(1<<host->this_id);
@@ -1174,8 +1332,9 @@
 	}
 	hostdata->state = NCR_700_HOST_BUSY;
 	hostdata->cmd = NULL;
+	/* clear any stale simple tag message */
 	hostdata->msgin[1] = 0;
-	dma_cache_wback((unsigned long)hostdata->msgin, sizeof(hostdata->msgin));
+	dma_cache_wback_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE);
 
 	if(id == 0xff) {
 		/* Selected as target, Ignore */
@@ -1188,6 +1347,32 @@
 	return resume_offset;
 }
 
+static inline void
+NCR_700_clear_fifo(struct Scsi_Host *host) {
+	const struct NCR_700_Host_Parameters *hostdata
+		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
+	if(hostdata->chip710) {
+		NCR_700_writeb(CLR_FIFO_710, host, CTEST8_REG);
+	} else {
+		NCR_700_writeb(CLR_FIFO, host, DFIFO_REG);
+	}
+}
+
+static inline void
+NCR_700_flush_fifo(struct Scsi_Host *host) {
+	const struct NCR_700_Host_Parameters *hostdata
+		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
+	if(hostdata->chip710) {
+		NCR_700_writeb(FLUSH_DMA_FIFO_710, host, CTEST8_REG);
+		udelay(10);
+		NCR_700_writeb(0, host, CTEST8_REG);
+	} else {
+		NCR_700_writeb(FLUSH_DMA_FIFO, host, DFIFO_REG);
+		udelay(10);
+		NCR_700_writeb(0, host, DFIFO_REG);
+	}
+}
+
 
 STATIC int
 NCR_700_start_command(Scsi_Cmnd *SCp)
@@ -1227,9 +1412,10 @@
 		NCR_700_clear_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
 	}
 
-	/* REQUEST_SENSE is asking for contingent I_T_L status.  If a
-	 * contingent allegiance condition exists, the device will
-	 * refuse all tags, so send the request sense as untagged */
+	/* REQUEST_SENSE is asking for contingent I_T_L(_Q) status.
+	 * If a contingent allegiance condition exists, the device
+	 * will refuse all tags, so send the request sense as untagged
+	 * */
 	if((hostdata->tag_negotiated & (1<<SCp->target))
 	   && (slot->tag != NCR_700_NO_TAG && SCp->cmnd[0] != REQUEST_SENSE)) {
 		hostdata->msgout[count++] = A_SIMPLE_TAG_MSG;
@@ -1244,8 +1430,6 @@
 		NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
 	}
 
-	dma_cache_wback((unsigned long)hostdata->msgout, count);
-
 	script_patch_16(hostdata->script, MessageCount, count);
 
 
@@ -1258,20 +1442,27 @@
 	/* finally plumb the beginning of the SG list into the script
 	 * */
 	script_patch_32_abs(hostdata->script, SGScriptStartAddress,
-			    virt_to_bus(&slot->SG[0].ins));
-	NCR_700_writeb(CLR_FIFO, SCp->host, DFIFO_REG);
+			    to32bit(&slot->pSG[0].ins));
+	NCR_700_clear_fifo(SCp->host);
 
-	/* set the synchronous period/offset */
 	if(slot->resume_offset == 0)
 		slot->resume_offset = hostdata->pScript;
+	/* now perform all the writebacks and invalidates */
+	dma_cache_wback((unsigned long)hostdata->msgout, count);
+	dma_cache_inv((unsigned long)hostdata->msgin, MSG_ARRAY_SIZE);
+	dma_cache_wback((unsigned long)SCp->cmnd, SCp->cmd_len);
+	dma_cache_inv((unsigned long)hostdata->status, 1);
+
+	/* set the synchronous period/offset */
 	NCR_700_writeb(NCR_700_get_SXFER(SCp->device),
-	     SCp->host, SXFER_REG);
+		       SCp->host, SXFER_REG);
+	NCR_700_writel(slot->temp, SCp->host, TEMP_REG);
+	NCR_700_writel(slot->resume_offset, SCp->host, DSP_REG);
+
 	/* allow interrupts here so that if we're selected we can take
 	 * a selection interrupt.  The script start may not be
 	 * effective in this case, but the selection interrupt will
 	 * save our command in that case */
-	NCR_700_writel(slot->temp, SCp->host, TEMP_REG);
-	NCR_700_writel(slot->resume_offset, SCp->host, DSP_REG);
 	restore_flags(flags);
 
 	return 1;
@@ -1342,8 +1533,8 @@
 
 			hostdata->state = NCR_700_HOST_BUSY;
 
-			printk(KERN_ERR "scsi%d: Bus Reset detected, executing command %p, slot %p, dsp %p[%04x]\n",
-			       host->host_no, SCp, SCp == NULL ? NULL : SCp->host_scribble, (void *)dsp, dsp - hostdata->pScript);
+			printk(KERN_ERR "scsi%d: Bus Reset detected, executing command %p, slot %p, dsp %08x[%04x]\n",
+			       host->host_no, SCp, SCp == NULL ? NULL : SCp->host_scribble, dsp, dsp - hostdata->pScript);
 
 			/* clear all the negotiated parameters */
 			for(SDp = host->host_queue; SDp != NULL; SDp = SDp->next)
@@ -1396,13 +1587,15 @@
 				printk("scsi%d (%d:%d) PHASE MISMATCH IN SEND MESSAGE %d remain, return %p[%04x], phase %s\n", host->host_no, pun, lun, count, (void *)temp, temp - hostdata->pScript, sbcl_to_string(NCR_700_readb(host, SBCL_REG)));
 #endif
 				resume_offset = hostdata->pScript + Ent_SendMessagePhaseMismatch;
-			} else if(dsp >= virt_to_bus(&slot->SG[0].ins) &&
-				  dsp <= virt_to_bus(&slot->SG[NCR_700_SG_SEGMENTS].ins)) {
+			} else if(dsp >= to32bit(&slot->pSG[0].ins) &&
+				  dsp <= to32bit(&slot->pSG[NCR_700_SG_SEGMENTS].ins)) {
 				int data_transfer = NCR_700_readl(host, DBC_REG) & 0xffffff;
-				int SGcount = (dsp - virt_to_bus(&slot->SG[0].ins))/sizeof(struct NCR_700_SG_List);
+				int SGcount = (dsp - to32bit(&slot->pSG[0].ins))/sizeof(struct NCR_700_SG_List);
 				int residual = NCR_700_data_residual(host);
 				int i;
 #ifdef NCR_700_DEBUG
+				__u32 naddr = NCR_700_readl(host, DNAD_REG);
+
 				printk("scsi%d: (%d:%d) Expected phase mismatch in slot->SG[%d], transferred 0x%x\n",
 				       host->host_no, pun, lun,
 				       SGcount, data_transfer);
@@ -1427,6 +1620,11 @@
 					slot->SG[SGcount].ins |= bS_to_host(data_transfer);
 					pAddr = bS_to_cpu(slot->SG[SGcount].pAddr);
 					pAddr += (count - data_transfer);
+#ifdef NCR_700_DEBUG
+					if(pAddr != naddr) {
+						printk("scsi%d (%d:%d) transfer mismatch pAddr=%lx, naddr=%lx, data_transfer=%d, residual=%d\n", host->host_no, pun, lun, (unsigned long)pAddr, (unsigned long)naddr, data_transfer, residual);
+					}
+#endif
 					slot->SG[SGcount].pAddr = bS_to_host(pAddr);
 				}
 				/* set the executed moves to nops */
@@ -1438,6 +1636,8 @@
 				/* and pretend we disconnected after
 				 * the command phase */
 				resume_offset = hostdata->pScript + Ent_MsgInDuringData;
+				/* make sure all the data is flushed */
+				NCR_700_flush_fifo(host);
 			} else {
 				__u8 sbcl = NCR_700_readb(host, SBCL_REG);
 				printk(KERN_ERR "scsi%d: (%d:%d) phase mismatch at %04x, phase %s\n",
@@ -1449,15 +1649,19 @@
 			printk(KERN_ERR "scsi%d: (%d:%d) GROSS ERROR\n",
 			       host->host_no, pun, lun);
 			NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16);
+		} else if(sstat0 & PARITY_ERROR) {
+			printk(KERN_ERR "scsi%d: (%d:%d) PARITY ERROR\n",
+			       host->host_no, pun, lun);
+			NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16);
 		} else if(dstat & SCRIPT_INT_RECEIVED) {
 			DEBUG(("scsi%d: (%d:%d) ====>SCRIPT INTERRUPT<====\n",
 			       host->host_no, pun, lun));
 			resume_offset = process_script_interrupt(dsps, dsp, SCp, host, hostdata);
 		} else if(dstat & (ILGL_INST_DETECTED)) {
-			printk(KERN_ERR "scsi%d: (%d:%d) Illegal Instruction detected at 0x%p[0x%x]!!!\n"
+			printk(KERN_ERR "scsi%d: (%d:%d) Illegal Instruction detected at 0x%08x[0x%x]!!!\n"
 			       "         Please email James.Bottomley@HansenPartnership.com with the details\n",
 			       host->host_no, pun, lun,
-			       (void *)dsp, dsp - hostdata->pScript);
+			       dsp, dsp - hostdata->pScript);
 			NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16);
 		} else if(dstat & (WATCH_DOG_INTERRUPT|ABORTED)) {
 			printk(KERN_ERR "scsi%d: (%d:%d) serious DMA problem, dstat=%02x\n",
@@ -1495,13 +1699,13 @@
 
 	if(resume_offset) {
 		if(hostdata->state != NCR_700_HOST_BUSY) {
-			printk(KERN_ERR "scsi%d: Driver error: resume at %p [%04x] with non busy host!\n",
-			       host->host_no, (void *)resume_offset, resume_offset - hostdata->pScript);
+			printk(KERN_ERR "scsi%d: Driver error: resume at 0x%08x [0x%04x] with non busy host!\n",
+			       host->host_no, resume_offset, resume_offset - hostdata->pScript);
 			hostdata->state = NCR_700_HOST_BUSY;
 		}
 
 		DEBUG(("Attempting to resume at %x\n", resume_offset));
-		NCR_700_writeb(CLR_FIFO, host, DFIFO_REG);
+		NCR_700_clear_fifo(host);
 		NCR_700_writel(resume_offset, host, DSP_REG);
 	} 
 	/* There is probably a technical no-no about this: If we're a
@@ -1579,6 +1783,7 @@
 	struct NCR_700_Host_Parameters *hostdata = 
 		(struct NCR_700_Host_Parameters *)SCp->host->hostdata[0];
 	__u32 move_ins;
+	int pci_direction;
 	struct NCR_700_command_slot *slot;
 	int hash;
 
@@ -1618,6 +1823,20 @@
 	printk("53c700: scsi%d, command ", SCp->host->host_no);
 	print_command(SCp->cmnd);
 #endif
+	if(SCp->device->tagged_supported && !SCp->device->tagged_queue
+	   && (hostdata->tag_negotiated &(1<<SCp->target)) == 0
+	   && NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING)) {
+		/* upper layer has indicated tags are supported.  We don't
+		 * necessarily believe it yet.
+		 *
+		 * NOTE: There is a danger here: the mid layer supports
+		 * tag queuing per LUN.  We only support it per PUN because
+		 * of potential reselection issues */
+		printk(KERN_INFO "scsi%d: (%d:%d) Enabling Tag Command Queuing\n", SCp->device->host->host_no, SCp->target, SCp->lun);
+		hostdata->tag_negotiated |= (1<<SCp->target);
+		NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
+		SCp->device->tagged_queue = 1;
+	}
 
 	if(hostdata->tag_negotiated &(1<<SCp->target)) {
 
@@ -1681,36 +1900,11 @@
 		hostdata->ITL_Hash_back[hash] = slot;
 	slot->ITL_back = NULL;
 
-		
-	/* This is f****g ridiculous; every low level HBA driver has
-	 * to determine the direction of the commands, why isn't this
-	 * done inside the scsi_lib !!??? */
 	switch (SCp->cmnd[0]) {
 	case REQUEST_SENSE:
 		/* clear the internal sense magic */
 		SCp->cmnd[6] = 0;
 		/* fall through */
-	case INQUIRY:
-	case MODE_SENSE:
-	case READ_6:
-	case READ_10:
-	case READ_12:
-	case READ_CAPACITY:
-	case READ_BLOCK_LIMITS:
-	case READ_TOC:
-		move_ins = SCRIPT_MOVE_DATA_IN;
-		break;
-	case MODE_SELECT:
-	case WRITE_6:
-	case WRITE_10:
-	case WRITE_12:
-		move_ins = SCRIPT_MOVE_DATA_OUT;
-		break;
-	case TEST_UNIT_READY:
-	case ALLOW_MEDIUM_REMOVAL:
-	case START_STOP:
-		move_ins = 0;
-		break;
 	default:
 		/* OK, get it from the command */
 		switch(SCp->sc_data_direction) {
@@ -1734,26 +1928,40 @@
 	}
 
 	/* now build the scatter gather list */
+	pci_direction = scsi_to_pci_dma_dir(SCp->sc_data_direction);
 	if(move_ins != 0) {
 		int i;
+		int sg_count;
+		dma_addr_t vPtr = 0;
+		__u32 count = 0;
+
+		if(SCp->use_sg) {
+			sg_count = pci_map_sg(hostdata->pci_dev, SCp->buffer,
+					      SCp->use_sg, pci_direction);
+		} else {
+			vPtr = pci_map_single(hostdata->pci_dev,
+					      SCp->request_buffer, 
+					      SCp->request_bufflen,
+					      pci_direction);
+			count = SCp->request_bufflen;
+			slot->dma_handle = vPtr;
+			sg_count = 1;
+		}
+			
 
-		for(i = 0; i < (SCp->use_sg ? SCp->use_sg : 1); i++) {
-			void *vPtr;
-			__u32 count;
+		for(i = 0; i < sg_count; i++) {
 
 			if(SCp->use_sg) {
-				vPtr = (((struct scatterlist *)SCp->buffer)[i].address);
-				count = ((struct scatterlist *)SCp->buffer)[i].length;
-			} else {
-				vPtr = SCp->request_buffer;
-				count = SCp->request_bufflen;
+				struct scatterlist *sg = SCp->buffer;
+
+				vPtr = sg_dma_address(&sg[i]);
+				count = sg_dma_len(&sg[i]);
 			}
+
 			slot->SG[i].ins = bS_to_host(move_ins | count);
 			DEBUG((" scatter block %d: move %d[%08x] from 0x%lx\n",
-			       i, count, slot->SG[i].ins, 
-			       virt_to_bus(vPtr)));
-			dma_cache_wback_inv((unsigned long)vPtr, count);
-			slot->SG[i].pAddr = bS_to_host(virt_to_bus(vPtr));
+			       i, count, slot->SG[i].ins, (unsigned long)vPtr));
+			slot->SG[i].pAddr = bS_to_host(vPtr);
 		}
 		slot->SG[i].ins = bS_to_host(SCRIPT_RETURN);
 		slot->SG[i].pAddr = 0;

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