Date: Wed, 10 Jun 1998 21:04:07 +0100
From: Richard Hirst <richard@sleepie.demon.co.uk>
To: linux-m68k@lists.linux-m68k.org
Subject: L68K: 53c710 patches for testing, take 5
Sender: owner-linux-m68k@phil.uni-sb.de

These are my latest patches for the 53c710 driver.  They should make it
work better on systems without bus snooping, and on 68060 based systems.
Fred Heitkamp has done a wonderful job of testing for me and the 53c710
on his 68060 Amiga is now basically working.

These patches are against a 2.1.105 tree.

For the greatest chance of success you might want to specify
"53c7xx=nosync:0,nodisconnect:0" in the boot parameters, and select
the CONFIG_060_WRITETHROUGH option under CONFIG_ADVANCED_CPU, although
niether of these may actually be necessary.

JES: Please dont integrate these patches - I still need to tidy up a bit
more, but I am posting them in the hope that a few more people will test
them first.

Richard.


--- linux68k-2.1.105/drivers/scsi/53c7xx.h	Wed Jun 10 19:15:47 1998
+++ linuxvme-2.1.105/drivers/scsi/53c7xx.h	Tue Jun  9 20:07:09 1998
@@ -1125,6 +1125,15 @@
 
     int flags;				/* CMD_* flags */
 
+    unsigned char      cmnd[12];	/* CDB, copied from Scsi_Cmnd */
+    int                result;		/* Copy to Scsi_Cmnd when done */
+
+    struct {				/* Private non-cached bounce buffer */
+        unsigned char buf[256];
+	u32	      addr;
+        u32           len;
+    } bounce;
+
 /*
  * SDTR and WIDE messages are an either/or affair
  * in this message, since we will go into message out and send
@@ -1547,7 +1556,7 @@
     NCR53c7x0_address_memory = (void *) (host)->base;			\
     NCR53c7x0_address_io = (unsigned int) (host)->io_port;		\
     NCR53c7x0_memory_mapped = ((struct NCR53c7x0_hostdata *) 		\
-	host->hostdata)-> options & OPTION_MEMORY_MAPPED 
+	host->hostdata[0])-> options & OPTION_MEMORY_MAPPED 
 
 #ifdef BIG_ENDIAN
 /* These could be more efficient, given that we are always memory mapped,
--- linux68k-2.1.105/drivers/scsi/53c7xx.c	Wed Jun 10 19:15:46 1998
+++ linuxvme-2.1.105/drivers/scsi/53c7xx.c	Wed Jun 10 18:56:47 1998
@@ -713,7 +713,7 @@
 	    h->max_id);
 	return -1;
     }
-    hostdata = (struct NCR53c7x0_hostdata *)h->hostdata;
+    hostdata = (struct NCR53c7x0_hostdata *)h->hostdata[0];
 
     save_flags(flags);
     cli();
@@ -746,7 +746,7 @@
     struct NCR53c7x0_hostdata *hostdata;
     if (!(h = find_host (host)))
 	return -1;
-    hostdata = (struct NCR53c7x0_hostdata *) h->hostdata;
+    hostdata = (struct NCR53c7x0_hostdata *) h->hostdata[0];
     if (on_or_off) 
 	hostdata->options |= OPTION_DISCONNECT;
     else
@@ -767,7 +767,7 @@
 static void 
 NCR53c7x0_driver_init (struct Scsi_Host *host) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     int i, j;
     u32 *ncrcurrent;
 
@@ -849,7 +849,7 @@
     int i, ccf;
     unsigned char revision;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     struct Scsi_Host *search;
     /* 
      * There are some things which we need to know about in order to provide
@@ -1075,40 +1075,13 @@
      * with another board.
      */
 
-#ifdef CONFIG_MVME16x
-    if (MACH_IS_MVME16x)
-    {
-        if (request_irq(MVME16x_IRQ_SCSI, NCR53c7x0_intr, 0, "SCSI-script", NULL))
-	    panic ("Couldn't get SCSI IRQ");
-#ifdef MVME16x_INTFLY
-        else if (request_irq(MVME16x_IRQ_FLY, NCR53c7x0_intr, 0, "SCSI-intfly", NULL))
-	    panic ("Couldn't get INT_FLY IRQ");
-#endif
-    }
-#endif
-#ifdef CONFIG_BVME6000
-    if (MACH_IS_BVME6000)
-    {
-        if (request_irq(BVME_IRQ_SCSI, NCR53c7x0_intr, 0, "SCSI-script", NULL))
-            panic ("Couldn't get SCSI IRQ");
-    }
-#endif
-#ifndef CONFIG_VME
     for (search = first_host; search && !(search->hostt == the_template &&
 	search->irq == host->irq && search != host); search=search->next);
 
     if (!search) {
-#ifdef CONFIG_AMIGA
-	if (request_irq(IRQ_AMIGA_PORTS, NCR53c7x0_intr, 0, "53c7xx", NCR53c7x0_intr))
-#else
-	if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7xx", NULL))
-#endif
+	if (request_irq(host->irq, NCR53c7x0_intr, 0, "53c7xx", NCR53c7x0_intr))
 	{
-	    printk("scsi%d : IRQ%d not free, detaching\n"
-	           "         You have either a configuration problem, or a\n"
-                   "         broken BIOS.  You may wish to manually assign\n"
-	           "         an interrupt to the NCR board rather than using\n"
-                   "         an automatic setting.\n", 
+	    printk("scsi%d : IRQ%d not free, detaching\n",
 		host->host_no, host->irq);
 	    scsi_unregister (host);
 	    return -1;
@@ -1117,7 +1090,6 @@
 	printk("scsi%d : using interrupt handler previously installed for scsi%d\n",
 	    host->host_no, search->host_no);
     }
-#endif
 
     if ((hostdata->run_tests && hostdata->run_tests(host) == -1) ||
         (hostdata->options & OPTION_DEBUG_TESTS_ONLY)) {
@@ -1236,20 +1208,28 @@
     */
     size += 256;
 #endif
+    /* Size should be < 8K, so we can fit it in two pages. */
+    if (size > 8192)
+      panic("53c7xx: hostdata > 8K");
 	flushsize = size;
-    instance = scsi_register (tpnt, size);
+    instance = scsi_register (tpnt, 4);
     if (!instance)
 	return -1;
+    instance->hostdata[0] = __get_free_pages(GFP_ATOMIC, 1);
+    if (instance->hostdata[0] == 0)
+        panic ("53c7xx: Couldn't get hostdata memory");
+    memset((void *)instance->hostdata[0], 0, 8192);
+    cache_push(virt_to_phys((void *)(instance->hostdata[0])), 8192);
+    cache_clear(virt_to_phys((void *)(instance->hostdata[0])), 8192);
+    kernel_set_cachemode(instance->hostdata[0], 8192, KERNELMAP_NOCACHE_SER);
 
     /* FIXME : if we ever support an ISA NCR53c7xx based board, we
        need to check if the chip is running in a 16 bit mode, and if so 
        unregister it if it is past the 16M (0x1000000) mark */
 
-    hostdata = (struct NCR53c7x0_hostdata *) 
-    	instance->hostdata;
+    hostdata = (struct NCR53c7x0_hostdata *)instance->hostdata[0];
     hostdata->size = size;
     hostdata->script_count = script_len / sizeof(u32);
-    hostdata = (struct NCR53c7x0_hostdata *) instance->hostdata;
     hostdata->board = board;
     hostdata->chip = chip;
 
@@ -1367,7 +1347,7 @@
 NCR53c7x0_init_fixup (struct Scsi_Host *host) {
     NCR53c7x0_local_declare();
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     unsigned char tmp;
     int i, ncr_to_memory, memory_to_ncr;
     u32 base;
@@ -1598,7 +1578,7 @@
 NCR53c7xx_run_tests (struct Scsi_Host *host) {
     NCR53c7x0_local_declare();
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     unsigned long timeout;
     u32 start;
     int failed, i;
@@ -1725,6 +1705,10 @@
 	    hostdata->test_completed = -1;
 	    start = virt_to_bus(hostdata->script) + hostdata->E_test_2;
 	    hostdata->state = STATE_RUNNING;
+	    /*
+	     * This cache_clear() seems a little suspect, but we dont
+	     * run test2 anyway...
+	     */
 	    if(!MACH_IS_MVME16x && !MACH_IS_BVME6000)
 		cache_clear(virt_to_bus(hostdata->script), flushsize);
 	    NCR53c7x0_write32 (DSA_REG, virt_to_bus(dsa));
@@ -1785,7 +1769,7 @@
     Scsi_Cmnd *c = cmd->cmd;
     struct Scsi_Host *host = c->host;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-    	host->hostdata;
+    	host->hostdata[0];
     int i;
 
     memcpy (cmd->dsa, hostdata->script + (hostdata->E_dsa_code_template / 4),
@@ -1888,7 +1872,7 @@
     Scsi_Cmnd *c = cmd->cmd;
     struct Scsi_Host *host = c->host;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-    	host->hostdata;
+    	host->hostdata[0];
     unsigned long flags;
     int left, found;
     volatile struct NCR53c7x0_cmd * linux_search;
@@ -2008,7 +1992,7 @@
 #endif
     u32 *dsp;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;		
+	host->hostdata[0];		
     unsigned long flags;
     NCR53c7x0_local_setup(host);
 
@@ -2088,7 +2072,7 @@
     int now_connected) {
     NCR53c7x0_local_declare();
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) 
-	host->hostdata;
+	host->hostdata[0];
     u32 *script;
     NCR53c7x0_local_setup(host);
 
@@ -2163,7 +2147,7 @@
 asynchronous (struct Scsi_Host *host, int target) {
     NCR53c7x0_local_declare();
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     NCR53c7x0_local_setup(host);
     set_synchronous (host, target, /* no offset */ 0, hostdata->saved_scntl3,
 	1);
@@ -2222,7 +2206,7 @@
 static void 
 synchronous (struct Scsi_Host *host, int target, char *msg) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     int desire, divisor, i, limit;
     unsigned char scntl3, sxfer;
 /* The diagnostic message fits on one line, even with max. width integers */
@@ -2284,7 +2268,7 @@
     int print;
     Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;		
+	host->hostdata[0];		
     u32 dsps,*dsp;	/* Argument of the INT instruction */
 
     NCR53c7x0_local_setup(host);
@@ -2297,7 +2281,7 @@
     /* RGH 200597:  Need to disable for BVME6000, as it gets Check Conditions
      * and then dies.  Seems to handle Check Condition at startup, but
      * not mid kernel build. */
-    if (dsps == A_int_norm_emulateintfly && c && c->result == 2)
+    if (dsps == A_int_norm_emulateintfly && cmd && cmd->result == 2)
         dsps = A_int_err_check_condition;
 #endif
 
@@ -2476,12 +2460,23 @@
 
     	patch_dsa_32 (cmd->dsa, dsa_cmdout, 0, 6);
 
-	c->cmnd[0] = REQUEST_SENSE;
-	c->cmnd[1] &= 0xe0;	/* Zero all but LUN */
-	c->cmnd[2] = 0;
-	c->cmnd[3] = 0;
-	c->cmnd[4] = sizeof(c->sense_buffer);
-	c->cmnd[5] = 0; 
+        /*
+         * The CDB is now mirrored in our local non-cached
+         * structure, but keep the old structure up to date as well,
+         * just in case anyone looks at it.
+         */
+
+	/*
+	 * XXX Need to worry about data buffer alignment/cache state
+	 * XXX here, but currently never get A_int_err_check_condition,
+	 * XXX so ignore problem for now.
+         */
+	cmd->cmnd[0] = c->cmnd[0] = REQUEST_SENSE;
+	cmd->cmnd[0] = c->cmnd[1] &= 0xe0;	/* Zero all but LUN */
+	cmd->cmnd[0] = c->cmnd[2] = 0;
+	cmd->cmnd[0] = c->cmnd[3] = 0;
+	cmd->cmnd[0] = c->cmnd[4] = sizeof(c->sense_buffer);
+	cmd->cmnd[0] = c->cmnd[5] = 0; 
 
 	/*
 	 * Disable dataout phase, and program datain to transfer to the 
@@ -2509,7 +2504,7 @@
 	 * status, etc are used.
     	 */
 
-	cmd->cmd->result = 0xffff;		
+	cmd->result = cmd->cmd->result = 0xffff;		
 
 	/* 
 	 * Restart command as a REQUEST SENSE.
@@ -2946,7 +2941,7 @@
     NCR53c7x0_local_declare();
     unsigned long flags;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     NCR53c7x0_local_setup(host);
 
     save_flags(flags);
@@ -3076,8 +3071,8 @@
 allocate_cmd (Scsi_Cmnd *cmd) {
     struct Scsi_Host *host = cmd->host;
     struct NCR53c7x0_hostdata *hostdata = 
-	(struct NCR53c7x0_hostdata *) host->hostdata;
-    void *real;			/* Real address */
+	(struct NCR53c7x0_hostdata *) host->hostdata[0];
+    u32 real;			/* Real address */
     int size;			/* Size of *tmp */
     struct NCR53c7x0_cmd *tmp;
     unsigned long flags;
@@ -3115,6 +3110,18 @@
 	size += 256;
 #endif
 /* FIXME: for ISA bus '7xx chips, we need to or GFP_DMA in here */
+
+#if 1
+        if (size > 4096)
+            panic ("53c7xx: allocate_cmd size > 4K");
+        real = get_free_page(GFP_ATOMIC);
+        if (real == 0)
+            panic ("53c7xx: Couldn't get memory for allocate_cmd");
+        memset((void *)real, 0, 4096);
+        cache_push(virt_to_phys((void *)real), 4096);
+        cache_clear(virt_to_phys((void *)real), 4096);
+        kernel_set_cachemode(real, 4096, KERNELMAP_NOCACHE_SER);
+#else
 	real = kmalloc (size, GFP_ATOMIC);
 	if (!real) {
 	    if (hostdata->options & OPTION_DEBUG_ALLOCATION)
@@ -3122,19 +3129,20 @@
 		    host->host_no, size);
 	    break;
 	}
+#endif
 	tmp = ROUNDUP(real, void *);
 #ifdef FORCE_DSA_ALIGNMENT
 	{
 	    if (((u32)tmp & 0xff) > CmdPageStart)
 		tmp = (struct NCR53c7x0_cmd *)((u32)tmp + 255);
 	    tmp = (struct NCR53c7x0_cmd *)(((u32)tmp & ~0xff) + CmdPageStart);
-#ifdef DEBUG
+#if 1
 	    printk ("scsi: size = %d, real = 0x%08x, tmp set to 0x%08x\n",
-			size, (u32)real, (u32)tmp);
+			size, real, (u32)tmp);
 #endif
 	}
 #endif
-	tmp->real = real;
+	tmp->real = (void *)real;
 	tmp->size = size;			
 	tmp->free = ((void (*)(void *, int)) kfree);
 	save_flags (flags);
@@ -3174,7 +3182,7 @@
     NCR53c7x0_local_declare();
     struct Scsi_Host *host = cmd->host;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-        host->hostdata;	
+        host->hostdata[0];	
     struct NCR53c7x0_cmd *tmp; 	/* NCR53c7x0_cmd structure for this command */
     int datain,  		/* Number of instructions per phase */
 	dataout;
@@ -3193,6 +3201,14 @@
     if (!(tmp = allocate_cmd (cmd)))
 	return NULL;
 
+    /*
+     * Copy CDB and initialised result fields from Scsi_Cmnd to NCR53c7x0_cmd.
+     * We do this because NCR53c7x0_cmd may have a special cache mode
+     * selected to cope with lack of bus snooping, etc.
+     */
+
+    memcpy(tmp->cmnd, cmd->cmnd, 12);
+    tmp->result = cmd->result;
 
     /*
      * Decide whether we need to generate commands for DATA IN,
@@ -3322,6 +3338,10 @@
     	hostdata->dsa_fixup(tmp);
 
     patch_dsa_32(tmp->dsa, dsa_next, 0, 0);
+    /*
+     * XXX is this giving 53c710 access to the Scsi_Cmnd in some way?
+     * Do we need to change it for caching reasons?
+     */
     patch_dsa_32(tmp->dsa, dsa_cmnd, 0, virt_to_bus(cmd));
 
     if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS) {
@@ -3383,7 +3403,7 @@
 	IDENTIFY (1, cmd->lun) : IDENTIFY (0, cmd->lun);
     patch_dsa_32(tmp->dsa, dsa_msgout, 1, virt_to_bus(tmp->select));
     patch_dsa_32(tmp->dsa, dsa_cmdout, 0, cmd->cmd_len);
-    patch_dsa_32(tmp->dsa, dsa_cmdout, 1, virt_to_bus(cmd->cmnd));
+    patch_dsa_32(tmp->dsa, dsa_cmdout, 1, virt_to_bus(tmp->cmnd));
     patch_dsa_32(tmp->dsa, dsa_dataout, 0, cmd_dataout ? 
     	    virt_to_bus (cmd_dataout)
 	: virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
@@ -3401,13 +3421,13 @@
  *	structure, and assign them to cmd->result when we're done.
  */
 #ifdef BIG_ENDIAN
-    patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&cmd->result) + 2);
+    patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&tmp->result) + 2);
     patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
-    patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&cmd->result) + 3);
+    patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&tmp->result) + 3);
 #else
-    patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&cmd->result) + 1);
+    patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&tmp->result) + 1);
     patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
-    patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&cmd->result));
+    patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&tmp->result));
 #endif
     patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, 1);
     patch_dsa_32(tmp->dsa, dsa_msgout_other, 1, 
@@ -3451,6 +3471,8 @@
  * Not bad, not good. We'll see.
  */
 
+    tmp->bounce.len = 0;	/* Assume aligned buffer */
+
     for (i = 0; cmd->use_sg ? (i < cmd->use_sg) : !i; cmd_datain += 4, 
 	cmd_dataout += 4, ++i) {
 	u32 buf = cmd->use_sg ? 
@@ -3460,7 +3482,57 @@
 	    ((struct scatterlist *)cmd->buffer)[i].length :
 	    cmd->request_bufflen;
 
+#if 1
+	/*
+	 * If we have buffers which are not aligned with 16 byte cache
+	 * lines, then we just hope nothing accesses the other parts of
+	 * those cache lines while the transfer is in progress.  That would
+	 * fill the cache, and subsequent reads of the dma data would pick
+	 * up the wrong thing.
+	 * XXX We need a bounce buffer to handle that correctly.
+	 */
+
+#if 0
+	if (datain || dataout)
+        {
+            if (buf & 0x0f)
+                printk("53c710: Hmm, scsi buffer at 0x%08x, len 0x%04x, cdb[0] = 0x%02x\n",
+                    buf, count, cmd->cmnd[0]);
+            else if (count & 0x0f)
+                printk("53c710: Hmm, scsi bufflen 0x%08x, cdb[0] = 0x%02x\n",
+                    count, cmd->cmnd[0]);
+	}
+#else
+	if (((buf & 15) || (count & 15)) && (datain || dataout))
+	{
+	    /* Bounce buffer needed */
+	    if (cmd->use_sg)
+		printk ("53c7xx: Non-aligned buffer with use_sg\n");
+	    else if (datain && dataout)
+                printk ("53c7xx: Non-aligned buffer with datain && dataout\n");
+            else if (count > 256)
+		printk ("53c7xx: Non-aligned transfer > 256 bytes\n");
+	    else if (datain)
+	    {
+		tmp->bounce.len = count;
+		tmp->bounce.addr = (u32)bus_to_virt(buf);
+		buf = virt_to_bus(tmp->bounce.buf);
+		tmp->bounce.buf[0] = 0xff;
+		tmp->bounce.buf[1] = 0xfe;
+		tmp->bounce.buf[2] = 0xfd;
+		tmp->bounce.buf[3] = 0xfc;
+	    }
+	    else /* dataout */
+	    {
+		memcpy ((void *)tmp->bounce.buf, (void *)buf, count);
+		buf = virt_to_bus(tmp->bounce.buf);
+	    }
+	}
+#endif
+#endif
 	if (datain) {
+	    /* Following 'buf' should be physical, not 'bus' */
+            cache_clear(buf, count);
 	    /* CALL other_in, WHEN NOT DATA_IN */  
 	    cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL | 
 		DCMD_TCI_IO) << 24) | 
@@ -3477,6 +3549,8 @@
 #endif
 	}
 	if (dataout) {
+	    /* Following 'buf' should be physical, not 'bus' */
+            cache_push(buf, count);
 	    /* CALL other_out, WHEN NOT DATA_OUT */
 	    cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL) << 24) | 
 		DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
@@ -3555,7 +3629,7 @@
 NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
     struct Scsi_Host *host = cmd->host;
     struct NCR53c7x0_hostdata *hostdata = 
-	(struct NCR53c7x0_hostdata *) host->hostdata;
+	(struct NCR53c7x0_hostdata *) host->hostdata[0];
     unsigned long flags;
     Scsi_Cmnd *tmp;
 
@@ -3809,7 +3883,7 @@
 	done = 1;
 	for (host = first_host; host && host->hostt == the_template;
 	    host = host->next) {
-	    hostdata = (struct NCR53c7x0_hostdata *) host->hostdata;
+	    hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0];
 	    cli();
 	    if (hostdata->issue_queue) {
 	    	if (hostdata->state == STATE_DISABLED) {
@@ -3881,7 +3955,7 @@
 intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
     NCR53c7x0_local_declare();
     struct NCR53c7x0_hostdata *hostdata = 
-    	(struct NCR53c7x0_hostdata *) host->hostdata;
+    	(struct NCR53c7x0_hostdata *) host->hostdata[0];
     unsigned char sstat0_sist0, sist1, 		/* Registers */
 	    fatal; 				/* Did a fatal interrupt 
 						   occur ? */
@@ -4072,7 +4146,7 @@
 	struct Scsi_Host *host = first_host;
 
 	while (cnt < 4096) {
-		printk ("%08x (+%6x): ", insn_log[i], (insn_log[i] - (u32)&(((struct NCR53c7x0_hostdata *)host->hostdata)->script))/4);
+		printk ("%08x (+%6x): ", insn_log[i], (insn_log[i] - (u32)&(((struct NCR53c7x0_hostdata *)host->hostdata[0])->script))/4);
 		if (++i == 4096)
 			i = 0;
 		cnt++;
@@ -4110,7 +4184,7 @@
     NCR53c7x0_local_declare();
     struct Scsi_Host *host;			/* Host we are looking at */
     unsigned char istat; 			/* Values of interrupt regs */
-    struct NCR53c7x0_hostdata *hostdata;	/* host->hostdata */
+    struct NCR53c7x0_hostdata *hostdata;	/* host->hostdata[0] */
     struct NCR53c7x0_cmd *cmd,			/* command which halted */
 	**cmd_prev_ptr;
     u32 *dsa;					/* DSA */
@@ -4145,7 +4219,7 @@
 							) {
     	    NCR53c7x0_local_setup(host);
 
-	    hostdata = (struct NCR53c7x0_hostdata *) host->hostdata;
+	    hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0];
 	    hostdata->dsp_changed = 0;
 	    interrupted = 0;
 	    have_intfly = 0;
@@ -4207,6 +4281,11 @@
 				host->host_no);
 				continue;
 			}
+                        /* Copy the result over now; may not be complete,
+			 * but subsequent tests may as well be done on
+                         * cached memory.
+                         */
+                        tmp->result = cmd->result;
 #if 0
 			printk ("scsi%d : looking at result of 0x%x\n",
 			    host->host_no, cmd->cmd->result);
@@ -4218,6 +4297,10 @@
 
 			search_found = 1;
 
+			if (cmd->bounce.len)
+			    memcpy ((void *)cmd->bounce.addr,
+				(void *)cmd->bounce.buf, cmd->bounce.len);
+
 			/* Important - remove from list _before_ done is called */
 			if (cmd_prev_ptr)
 			    *cmd_prev_ptr = (struct NCR53c7x0_cmd *) cmd->next;
@@ -4387,7 +4470,7 @@
     NCR53c7x0_local_declare();
 #endif
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
 /* FIXME : this probably should change for production kernels; at the 
    least, counter should move to a per-host structure. */
     static int counter = 5;
@@ -4564,7 +4647,7 @@
     u32 dbc_dcmd, *dsp, *dsp_next;
     unsigned char dcmd, sbcl;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-    	host->hostdata;
+    	host->hostdata[0];
     int residual;
     enum {ACTION_ABORT, ACTION_ABORT_PRINT, ACTION_CONTINUE} action = 
 	ACTION_ABORT_PRINT;
@@ -4834,7 +4917,7 @@
      */
 
     if (retry == NEVER) {
-    	printk(KERN_ALERT "          mail ricahrd@sleepie.demon.co.uk\n");
+    	printk(KERN_ALERT "          mail richard@sleepie.demon.co.uk\n");
     	FATAL (host);
     }
 }
@@ -4854,7 +4937,7 @@
 intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
     NCR53c7x0_local_declare();
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     unsigned char dstat;	/* DSTAT */	
     u32 *dsp,
 	*next_dsp,		/* Current dsp */
@@ -5113,7 +5196,7 @@
 	/* Remove virtual addresses to reduce output, as they are the same */
 	sprintf(buf, "%s0x%x (+%x) : 0x%08x 0x%08x", 
 	    (prefix ? prefix : ""), (u32)insn, ((u32)insn -
-		(u32)&(((struct NCR53c7x0_hostdata *)host->hostdata)->script))/4, 
+		(u32)&(((struct NCR53c7x0_hostdata *)host->hostdata[0])->script))/4, 
 	    insn[0], insn[1]);
 #endif
 	tmp = buf + strlen(buf);
@@ -5160,7 +5243,7 @@
     NCR53c7x0_local_declare();
     struct Scsi_Host *host = cmd->host;
     struct NCR53c7x0_hostdata *hostdata = host ? (struct NCR53c7x0_hostdata *) 
-	host->hostdata : NULL;
+	host->hostdata[0] : NULL;
     unsigned long flags;
     struct NCR53c7x0_cmd *curr, **prev;
     Scsi_Cmnd *me, **last;
@@ -5251,7 +5334,8 @@
          &(curr->next), curr = (struct NCR53c7x0_cmd *) curr->next);
 
     if (curr) {
-	if ((cmd->result & 0xff) != 0xff && (cmd->result & 0xff00) != 0xff00) {
+	if ((curr->result & 0xff) != 0xff && (curr->result & 0xff00) != 0xff00) {
+            cmd->result = curr->result;
 	    if (prev)
 		*prev = (struct NCR53c7x0_cmd *) curr->next;
 	    curr->next = (struct NCR53c7x0_cmd *) hostdata->free;
@@ -5282,13 +5366,14 @@
 	cmd->host_scribble = NULL;
     }
 
-    if (((cmd->result & 0xff00) == 0xff00) ||
-	((cmd->result & 0xff) == 0xff)) {
+    if (curr == NULL || ((curr->result & 0xff00) == 0xff00) ||
+		((curr->result & 0xff) == 0xff)) {
 	printk ("scsi%d : did this command ever run?\n", host->host_no);
-	cmd->result = DID_ABORT << 16;
+	    cmd->result = DID_ABORT << 16;
     } else {
 	printk ("scsi%d : probably lost INTFLY, normal completion\n", 
 	    host->host_no);
+        cmd->result = curr->result;
 /* 
  * FIXME : We need to add an additional flag which indicates if a 
  * command was ever counted as BUSY, so if we end up here we can
@@ -5341,7 +5426,7 @@
     Scsi_Cmnd *nuke_list = NULL;
     struct Scsi_Host *host = cmd->host;
     struct NCR53c7x0_hostdata *hostdata = 
-    	(struct NCR53c7x0_hostdata *) host->hostdata;
+    	(struct NCR53c7x0_hostdata *) host->hostdata[0];
 
     NCR53c7x0_local_setup(host);
     save_flags(flags);
@@ -5410,7 +5495,7 @@
 static int 
 insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) {
     struct NCR53c7x0_hostdata *hostdata = 
-	(struct NCR53c7x0_hostdata *) cmd->host->hostdata;
+	(struct NCR53c7x0_hostdata *) cmd->host->hostdata[0];
     struct NCR53c7x0_cmd *ncmd = 
 	(struct NCR53c7x0_cmd *) cmd->host_scribble;
     int offset = 0, buffers;
@@ -5479,6 +5564,16 @@
     char *where;
     u32 *ptr;
     NCR53c7x0_local_setup (cmd->host);
+
+    if (check_address ((unsigned long) ncmd,sizeof (struct NCR53c7x0_cmd)) == 0)
+    {
+	printk("\nNCR53c7x0_cmd fields:\n");
+	printk("  bounce.len=0x%x, addr=0x%0x, buf[]=0x%02x %02x %02x %02x\n",
+	    ncmd->bounce.len, ncmd->bounce.addr, ncmd->bounce.buf[0],
+	    ncmd->bounce.buf[1], ncmd->bounce.buf[2], ncmd->bounce.buf[3]);
+	printk("  result=%04x, cdb[0]=0x%02x\n", ncmd->result, ncmd->cmnd[0]);
+    }
+
     for (i = 0; i < 2; ++i) {
 	if (check_address ((unsigned long) ncmd, 
 	    sizeof (struct NCR53c7x0_cmd)) == -1) 
@@ -5516,7 +5611,7 @@
 static void 
 print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     int i, len;
     char *ptr;
     Scsi_Cmnd *cmd;
@@ -5558,6 +5653,7 @@
     cmd = (Scsi_Cmnd *) bus_to_virt(dsa[hostdata->dsa_cmnd / sizeof(u32)]);
     printk("        + %d : dsa_cmnd = 0x%x ", hostdata->dsa_cmnd,
 	   (u32) virt_to_bus(cmd));
+    /* XXX Maybe we should access cmd->host_scribble->result here. RGH */
     if (cmd) {
 	printk("               result = 0x%x, target = %d, lun = %d, cmd = ",
 	    cmd->result, cmd->target, cmd->lun);
@@ -5590,7 +5686,7 @@
 static void 
 print_queues (struct Scsi_Host *host) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     u32 *dsa, *next_dsa;
     volatile u32 *ncrcurrent;
     int left;
@@ -5673,7 +5769,7 @@
 print_lots (struct Scsi_Host *host) {
     NCR53c7x0_local_declare();
     struct NCR53c7x0_hostdata *hostdata = 
-	(struct NCR53c7x0_hostdata *) host->hostdata;
+	(struct NCR53c7x0_hostdata *) host->hostdata[0];
     u32 *dsp_next, *dsp, *dsa, dbc_dcmd;
     unsigned char dcmd, sbcl;
     int i, size;
@@ -5695,7 +5791,7 @@
 	        "         DSPS=0x%x, TEMP=0x%x (virt 0x%p), DMODE=0x%x\n"
 		"         SXFER=0x%x, SCNTL3=0x%x\n"
 		"         %s%s%sphase=%s, %d bytes in SCSI FIFO\n"
-		"         STEST0=0x%x\n",
+		"         SCRATCH=0x%x, saved2_dsa=0x%0lx\n",
 	    host->host_no, dbc_dcmd, NCR53c7x0_read32(DNAD_REG),
 		bus_to_virt(NCR53c7x0_read32(DNAD_REG)),
 	    virt_to_bus(dsa), dsa,
@@ -5712,8 +5808,9 @@
 	    	SSTAT1_REG : SSTAT2_REG)),
 	    (NCR53c7x0_read8 ((hostdata->chip / 100) == 8 ? 
 		SSTAT1_REG : SSTAT2_REG) & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT,
-	    ((hostdata->chip / 100) == 8) ?
-		NCR53c7x0_read8 (STEST0_REG_800) : 0);
+	    ((hostdata->chip / 100) == 8) ? NCR53c7x0_read8 (STEST0_REG_800) :
+		NCR53c7x0_read32(SCRATCHA_REG_800),
+	    hostdata->saved2_dsa);
 	printk ("scsi%d : DSP 0x%lx (virt 0x%p) ->\n", host->host_no, 
 	    virt_to_bus(dsp), dsp);
     	for (i = 6; i > 0; --i, dsp += size)
@@ -5748,7 +5845,7 @@
     NCR53c7x0_local_declare();
     unsigned long flags;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     NCR53c7x0_local_setup(host);
     save_flags (flags);
     cli();
@@ -5789,7 +5886,7 @@
 static void 
 hard_reset (struct Scsi_Host *host) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     unsigned long flags;
     save_flags (flags);
     cli();
@@ -5824,7 +5921,7 @@
 static Scsi_Cmnd *
 return_outstanding_commands (struct Scsi_Host *host, int free, int issue) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     struct NCR53c7x0_cmd *c;
     int i;
     u32 *ncrcurrent;
@@ -5890,7 +5987,7 @@
 static int 
 disable (struct Scsi_Host *host) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     unsigned long flags;
     Scsi_Cmnd *nuke_list, *tmp;
     save_flags(flags);
@@ -5927,12 +6024,15 @@
 ncr_halt (struct Scsi_Host *host) {
     NCR53c7x0_local_declare();
     unsigned long flags;
-    unsigned char istat, tmp;
+    unsigned char istat, tmp, scnt = 0;
+    static unsigned char stats[2][64];
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     int stage;
     NCR53c7x0_local_setup(host);
 
+    printk("scsi%d : HALTING\n", host->host_no);
+
     save_flags(flags);
     cli();
     /* Stage 0 : eat all interrupts
@@ -5941,15 +6041,21 @@
        Stage 3 : eat all interrupts
      */
     for (stage = 0;;) {
+	udelay(1000);
+	if (scnt == 64)
+	    scnt--;
 	if (stage == 1) {
 	    NCR53c7x0_write8(hostdata->istat, ISTAT_ABRT);
 	    ++stage;
 	}
 	istat = NCR53c7x0_read8 (hostdata->istat);
+	stats[0][scnt] = 'i'; stats[1][scnt++] = istat;
 	if (istat & ISTAT_SIP) {
 	    tmp = NCR53c7x0_read8(SSTAT0_REG);
+	    stats[0][scnt] = 's'; stats[1][scnt++] = tmp;
 	} else if (istat & ISTAT_DIP) {
 	    tmp = NCR53c7x0_read8(DSTAT_REG);
+	    stats[0][scnt] = 'd'; stats[1][scnt++] = tmp;
 	    if (stage == 2) {
 		if (tmp & DSTAT_ABRT) {
 		    NCR53c7x0_write8(hostdata->istat, 0);
@@ -5972,6 +6078,8 @@
 #if 0
     print_lots (host);
 #endif
+    for (tmp = 0; tmp < scnt; tmp++)
+	printk("  %cstat = 0x%02x\n", stats[0][tmp], stats[1][tmp]);
     return 0;
 }
 
@@ -6007,7 +6115,7 @@
 static void
 dump_events (struct Scsi_Host *host, int count) {
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     struct NCR53c7x0_event event;
     int i;
     unsigned long flags;
@@ -6071,7 +6179,7 @@
 int 
 NCR53c7x0_release(struct Scsi_Host *host) {
     struct NCR53c7x0_hostdata *hostdata = 
-	(struct NCR53c7x0_hostdata *) host->hostdata;
+	(struct NCR53c7x0_hostdata *) host->hostdata[0];
     struct NCR53c7x0_cmd *cmd, *tmp;
     shutdown (host);
     if (host->irq != IRQ_NONE)
--- linux68k-2.1.105/drivers/scsi/bvme6000.h	Wed Jun 10 19:15:54 1998
+++ linuxvme-2.1.105/drivers/scsi/bvme6000.h	Tue Jun  9 20:07:10 1998
@@ -36,7 +36,7 @@
 		       bios_param:          scsicam_bios_param,   \
 		       can_queue:           24,       \
 		       this_id:             7,               \
-		       sg_tablesize:        127,          \
+		       sg_tablesize:        63,          \
 		       cmd_per_lun:	    3,     \
 		       use_clustering:      DISABLE_CLUSTERING }
 #endif
--- linux68k-2.1.105/drivers/scsi/mvme16x.h	Wed Jun 10 19:15:58 1998
+++ linuxvme-2.1.105/drivers/scsi/mvme16x.h	Tue Jun  9 20:07:10 1998
@@ -36,7 +36,7 @@
 		       bios_param:          scsicam_bios_param,   \
 		       can_queue:           24,       \
 		       this_id:             7,               \
-		       sg_tablesize:        127,          \
+		       sg_tablesize:        63,          \
 		       cmd_per_lun:	    3,     \
 		       use_clustering:      DISABLE_CLUSTERING }
 #endif
--- linux68k-2.1.105/drivers/scsi/amiga7xx.h	Wed Jan  7 17:09:45 1998
+++ linuxvme-2.1.105/drivers/scsi/amiga7xx.h	Tue Jun  9 20:07:10 1998
@@ -35,7 +35,7 @@
 		       bios_param:          scsicam_bios_param,   \
 		       can_queue:           24,       \
 		       this_id:             7,               \
-		       sg_tablesize:        127,          \
+		       sg_tablesize:        63,          \
 		       cmd_per_lun:	    3,     \
 		       use_clustering:      DISABLE_CLUSTERING }
 #endif
