Date: Sun, 31 May 1998 23:18:07 +0100
From: Richard Hirst <richard@sleepie.demon.co.uk>
To: fheitka@ibm.net
Cc: richard.hirst@net-tel.co.uk, linux-m68k@lists.linux-m68k.org
Subject: L68K: 53c710 driver patches for testing
Sender: owner-linux-m68k@phil.uni-sb.de

Hi,
  Here are some patches for the 53c7xx.c SCSI driver, which hopefully make
it work better, even on the 68060 where there is no bus snooping.

I was not able to disable bus snooping on my 68060 board, so I have not been
able to test this as well as I would have liked.  My system does still
boot from SCSI, but I make no promises that it wont trash your disks....

NOTE:  Jes, please don't integrate this patch.  It is for testing only, and
needs some further changes before it is integrated.  I wont supply patches
relative to this one.

This should be applied on top of my "2.1.101 patches for VME" diff that I
sent to the list a few days ago. [Fred, undo the changes you made to get
test 1 running before applying this].

Those VME patches introduced an option to run the 68060 with write-back
caching for supervisor accesses.  For the best chances of success with
this patch, that option should be enabled - if it works, test with
normal copyback caching and report back.

First a comment.  53c7xx.c has several calls to cache_push()
to flush the scripts area through to memory, where the address is wrapped
in a virt_to_bus() macro.  Surely those should be virt_to_phys()?  The
cache_push-ing is probably no longer needed anyway, but in the past I guess
that it has been pushing the wrong thing for Hades (I am not well up on
Amiga/Atari h/w - is Hades something that uses the 53c710 driver?).

These patches change the driver so that it calls get_free_pages() for
critical areas, and sets the cache mode on those patches to non-cached
serialized.  The 53c710 used to pick up the SCSI CDB and write the status
back directly from/to the Scsi_Cmnd structure.  Those transfers are now
done via local non-cached memory.  I don't yet free the pages I allocate,
so expect a memory leak if you run this as a module.  I have reduced the
maximum scater/gather list length from 127 to 63, so I can build a worst-case
command in one page.

You will see messages like:

53c710: Hmm, scsi buffer at 0x007dc8be, len 0x0010, cdb[0] = 0x03

as your system boots.  These indicate transfers to/from buffers which are
not cache-line aligned.  I need to introduce a bounce-buffer to handle those
properly, but for the moment I just hope nothing accesses the other half
of those split cache lines before the transfer completes..  this seems to
be a problem with buffers for Request Sense, Inquiry, and Read Capacity.
Alternatively, we could fix the higher scsi layers to align them..

Lots of people have had problems with this driver, so I am expecting lots
of success reports ;)

Richard.

--- linux68k-2.1.101+submited-patch/drivers/scsi/53c7xx.h	Tue Apr  7 10:26:05 1998
+++ linuxvme-2.1.101/drivers/scsi/53c7xx.h	Sun May 31 17:32:04 1998
@@ -1125,6 +1125,9 @@
 
     int flags;				/* CMD_* flags */
 
+    unsigned char      cmnd[12];	/* CDB, copied from Scsi_Cmnd */
+    int                result;		/* Copy to Scsi_Cmnd when done */
+
 /*
  * SDTR and WIDE messages are an either/or affair
  * in this message, since we will go into message out and send
@@ -1547,7 +1550,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.101+submited-patch/drivers/scsi/53c7xx.c	Sun May 31 21:13:57 1998
+++ linuxvme-2.1.101/drivers/scsi/53c7xx.c	Sun May 31 21:55:41 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
@@ -1236,20 +1236,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 +1375,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 +1606,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 +1733,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 +1797,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 +1900,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 +2020,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 +2100,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 +2175,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 +2234,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 +2296,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 +2309,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 +2488,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 +2532,7 @@
 	 * status, etc are used.
     	 */
 
-	cmd->cmd->result = 0xffff;		
+	cmd->result = cmd->cmd->result = 0xffff;		
 
 	/* 
 	 * Restart command as a REQUEST SENSE.
@@ -2946,7 +2969,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 +3099,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 +3138,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 +3157,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 +3210,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 +3229,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 +3366,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 +3431,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 +3449,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, 
@@ -3460,7 +3508,28 @@
 	    ((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 (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]);
+	}
+#endif
 	if (datain) {
+            cache_clear(virt_to_phys((void *)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 +3546,7 @@
 #endif
 	}
 	if (dataout) {
+            cache_push(virt_to_phys((void *)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 +3625,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 +3879,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 +3951,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 +4142,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 +4180,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 +4215,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 +4277,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);
@@ -4387,7 +4462,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 +4639,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;
@@ -4854,7 +4929,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 +5188,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 +5235,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 +5326,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 +5358,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 +5418,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 +5487,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;
@@ -5516,7 +5593,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 +5635,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 +5668,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 +5751,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;
@@ -5748,7 +5826,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 +5867,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 +5902,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 +5968,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);
@@ -5929,7 +6007,7 @@
     unsigned long flags;
     unsigned char istat, tmp;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     int stage;
     NCR53c7x0_local_setup(host);
 
@@ -6007,7 +6085,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 +6149,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.101+submited-patch/drivers/scsi/bvme6000.h	Sun May 31 21:13:57 1998
+++ linuxvme-2.1.101/drivers/scsi/bvme6000.h	Sat May 30 22:38:13 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.101+submited-patch/drivers/scsi/mvme16x.h	Sun May 31 21:13:57 1998
+++ linuxvme-2.1.101/drivers/scsi/mvme16x.h	Sun May 31 20:05:53 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.101+submited-patch/drivers/scsi/amiga7xx.h	Wed Jan  7 17:09:45 1998
+++ linuxvme-2.1.101/drivers/scsi/amiga7xx.h	Sun May 31 20:06:06 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
