patch-2.1.113 linux/drivers/scsi/53c7xx.c

Next file: linux/drivers/scsi/53c7xx.h
Previous file: linux/drivers/net/eepro100.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.112/linux/drivers/scsi/53c7xx.c linux/drivers/scsi/53c7xx.c
@@ -40,7 +40,8 @@
  *
  * Options for the NCR7xx driver
  *
- * nosync:0		-	disables synchronous negotiation
+ * noasync:0		-	disables sync and asynchronous negotiation
+ * nosync:0		-	disables synchronous negotiation (does async)
  * nodisconnect:0	-	disables disconnection
  * validids:0x??	-	Bitmask field that disallows certain ID's.
  *			-	e.g.	0x03	allows ID 0,1
@@ -273,6 +274,15 @@
 #define VALID_IDS
 #endif
 
+#ifdef CONFIG_BVME6000
+#include <asm/pgtable.h>
+#include <asm/bvme6000hw.h>
+
+#define BIG_ENDIAN
+#define NO_IO_SPACE
+#define VALID_IDS
+#endif
+
 #include "scsi.h"
 #include "hosts.h"
 #include "53c7xx.h"
@@ -315,7 +325,6 @@
 static int disable (struct Scsi_Host *host);
 static int NCR53c7xx_run_tests (struct Scsi_Host *host);
 static void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
-static void do_NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
 static int ncr_halt (struct Scsi_Host *host);
 static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd 
     *cmd);
@@ -347,7 +356,6 @@
 #ifdef FORCE_DSA_ALIGNMENT
 int CmdPageStart = (0 - Ent_dsa_zero - sizeof(struct NCR53c7x0_cmd)) & 0xff;
 #endif
-int flushsize;
 
 static char *setup_strings[] =
 	{"","","","","","","",""};
@@ -705,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();
@@ -738,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
@@ -759,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;
 
@@ -791,9 +799,6 @@
     	hostdata->initiate_sdtr = 0;
     hostdata->talked_to = 0;
     hostdata->idle = 1;
-
-    if (!MACH_IS_MVME16x)
-	cache_push(virt_to_bus(hostdata->script), flushsize);
 }
 
 /* 
@@ -841,7 +846,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
@@ -864,12 +869,17 @@
 	hostdata->valid_ids[i] = 1;	/* Default all ID's to scan */
 
     /* Parse commandline flags */
-    if (check_setup_strings("nosync",&flags,&val,buf))
+    if (check_setup_strings("noasync",&flags,&val,buf))
     {
 	hostdata->options |= OPTION_NO_ASYNC;
 	hostdata->options &= ~(OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS);
     }
 
+    if (check_setup_strings("nosync",&flags,&val,buf))
+    {
+	hostdata->options &= ~(OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS);
+    }
+
     if (check_setup_strings("nodisconnect",&flags,&val,buf))
 	hostdata->options &= ~OPTION_DISCONNECT;
 
@@ -982,26 +992,23 @@
      * default value may not be optimal anyway.
      * Even worse, it may never have been set up since reset.
      */
-	hostdata->saved_ctest7 = NCR53c7x0_read8(CTEST7_REG) & CTEST7_SAVE;
-	revision = (NCR53c7x0_read8(CTEST8_REG) & 0xF0) >> 4;
-	switch (revision) {
-		case 1:
-			revision = 0;
-			break;
-		case 2:
-			revision = 1;
-			break;
-		case 4: 
-			revision = 2;
-			break;
-		case 8:
-			revision = 3;
-			break;
-		default:
-			revision = 255;
-			break;
-	}
-	printk("scsi%d: Revision 0x%x\n",host->host_no,revision);
+    hostdata->saved_ctest7 = NCR53c7x0_read8(CTEST7_REG) & CTEST7_SAVE;
+    revision = (NCR53c7x0_read8(CTEST8_REG) & 0xF0) >> 4;
+    switch (revision) {
+	case 1: revision = 0;    break;
+	case 2: revision = 1;    break;
+	case 4: revision = 2;    break;
+	case 8: revision = 3;    break;
+	default: revision = 255; break;
+    }
+    printk("scsi%d: Revision 0x%x\n",host->host_no,revision);
+
+    if ((revision == 0 || revision == 255) && (hostdata->options & (OPTION_SYNCHRONOUS|OPTION_DISCONNECT|OPTION_ALWAYS_SYNCHRONOUS)))
+    {
+	printk ("scsi%d: Disabling sync working and disconnect/reselect\n",
+							host->host_no);
+	hostdata->options &= ~(OPTION_SYNCHRONOUS|OPTION_DISCONNECT|OPTION_ALWAYS_SYNCHRONOUS);
+    }
 
     /*
      * On NCR53c700 series chips, DCNTL controls the SCSI clock divisor,
@@ -1070,28 +1077,13 @@
      * with another board.
      */
 
-#ifdef CONFIG_MVME16x
-    if (request_irq(IRQ_MVME16x_SCSI, do_NCR53c7x0_intr, 0, "SCSI-script", NULL))
-	panic ("Couldn't get SCSI IRQ");
-#ifdef MVME16x_INTFLY
-    else if (request_irq(IRQ_MVME16x_FLY, do_NCR53c7x0_intr, 0, "SCSI-intfly", NULL))
-	panic ("Couldn't get INT_FLY IRQ");
-#endif
-#else
     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, do_NCR53c7x0_intr, 0, "53c7xx", NCR53c7x0_intr)) {
-#else
-	if (request_irq(host->irq, do_NCR53c7x0_intr, SA_INTERRUPT, "53c7xx", NULL)) {
-#endif
-	    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", 
+	if (request_irq(host->irq, NCR53c7x0_intr, 0, "53c7xx", NCR53c7x0_intr))
+	{
+	    printk("scsi%d : IRQ%d not free, detaching\n",
 		host->host_no, host->irq);
 	    scsi_unregister (host);
 	    return -1;
@@ -1100,7 +1092,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)) {
@@ -1219,20 +1210,27 @@
     */
     size += 256;
 #endif
-	flushsize = size;
-    instance = scsi_register (tpnt, size);
+    /* Size should be < 8K, so we can fit it in two pages. */
+    if (size > 8192)
+      panic("53c7xx: hostdata > 8K");
+    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;
 
@@ -1292,10 +1290,12 @@
 	    t = (void *)((u32)t + 255);
 	t = (void *)(((u32)t & ~0xff) + CmdPageStart);
         hostdata->free = t;
+#if 0
 	printk ("scsi: Registered size increased by 256 to %d\n", size);
 	printk ("scsi: CmdPageStart = 0x%02x\n", CmdPageStart);
 	printk ("scsi: tmp = 0x%08x, hostdata->free set to 0x%08x\n",
 			(u32)tmp, (u32)t);
+#endif
     }
 #else
     hostdata->free = ROUNDUP(tmp, void *);
@@ -1350,7 +1350,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;
@@ -1407,7 +1407,7 @@
      * register.  Make sure SCRIPTS start automagically.
      */
 
-#if defined(CONFIG_MVME16x)
+#if defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
     /* We know better what we want than 16xBug does! */
     tmp = DMODE_10_BL_8 | DMODE_10_FC2;
 #else
@@ -1557,9 +1557,6 @@
 
     printk("scsi%d : NCR code relocated to 0x%lx (virt 0x%p)\n", host->host_no,
 	virt_to_bus(hostdata->script), hostdata->script);
-
-    if (!MACH_IS_MVME16x)
-	cache_push(virt_to_bus(hostdata->script), flushsize);
 }
 
 /*
@@ -1581,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;
@@ -1613,8 +1610,6 @@
 	start = virt_to_bus (hostdata->script) + hostdata->E_test_1;
     	hostdata->state = STATE_RUNNING;
 	printk ("scsi%d : test 1", host->host_no);
-	if (!MACH_IS_MVME16x)
-	    cache_push(virt_to_bus(hostdata->script), flushsize);
 	NCR53c7x0_write32 (DSP_REG, start);
 	if (hostdata->options & OPTION_DEBUG_TRACE)
 	    NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM |
@@ -1708,8 +1703,6 @@
 	    hostdata->test_completed = -1;
 	    start = virt_to_bus(hostdata->script) + hostdata->E_test_2;
 	    hostdata->state = STATE_RUNNING;
-	    if(!MACH_IS_MVME16x)
-		cache_clear(virt_to_bus(hostdata->script), flushsize);
 	    NCR53c7x0_write32 (DSA_REG, virt_to_bus(dsa));
 	    NCR53c7x0_write32 (DSP_REG, start);
 	    if (hostdata->options & OPTION_DEBUG_TRACE)
@@ -1768,7 +1761,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),
@@ -1815,11 +1808,6 @@
 
     patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
 	dsa_temp_addr_dsa_value, virt_to_bus(&cmd->dsa_addr));
-
-    if (!MACH_IS_MVME16x) {
-	cache_push(virt_to_bus(hostdata->script), flushsize);
-    	cache_push(virt_to_bus(cmd->dsa), flushsize);
-    }
 }
 
 /* 
@@ -1871,7 +1859,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;
@@ -1991,7 +1979,7 @@
 #endif
     u32 *dsp;
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;		
+	host->hostdata[0];		
     unsigned long flags;
     NCR53c7x0_local_setup(host);
 
@@ -2071,7 +2059,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);
 
@@ -2146,7 +2134,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);
@@ -2205,7 +2193,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 */
@@ -2267,7 +2255,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);
@@ -2280,7 +2268,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
 
@@ -2459,12 +2447,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 
@@ -2492,7 +2491,7 @@
 	 * status, etc are used.
     	 */
 
-	cmd->cmd->result = 0xffff;		
+	cmd->result = cmd->cmd->result = 0xffff;		
 
 	/* 
 	 * Restart command as a REQUEST SENSE.
@@ -2888,9 +2887,6 @@
 	    host->host_no, (unsigned) dsps);
 	return SPECIFIC_INT_PANIC;
     }
-
-    if (!MACH_IS_MVME16x)
-	flush_cache_all();
 }
 
 /* 
@@ -2928,11 +2924,8 @@
 NCR53c7x0_soft_reset (struct Scsi_Host *host) {
     NCR53c7x0_local_declare();
     unsigned long flags;
-#ifdef CONFIG_MVME16x
-    volatile unsigned long v;
-#endif
     struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
-	host->hostdata;
+	host->hostdata[0];
     NCR53c7x0_local_setup(host);
 
     save_flags(flags);
@@ -2941,15 +2934,19 @@
     /* Disable scsi chip and s/w level 7 ints */
 
 #ifdef CONFIG_MVME16x
-    v = *(volatile unsigned long *)0xfff4006c;
-    v &= ~0x8000;
-    *(volatile unsigned long *)0xfff4006c = v;
-    v = *(volatile unsigned long *)0xfff4202c;
-    v &= ~0x10;
-    *(volatile unsigned long *)0xfff4202c = v;
-#else
-    /* Anything specific for your hardware? */
+    if (MACH_IS_MVME16x)
+    {
+        volatile unsigned long v;
+
+        v = *(volatile unsigned long *)0xfff4006c;
+        v &= ~0x8000;
+        *(volatile unsigned long *)0xfff4006c = v;
+        v = *(volatile unsigned long *)0xfff4202c;
+        v &= ~0x10;
+        *(volatile unsigned long *)0xfff4202c = v;
+    }
 #endif
+    /* Anything specific for your hardware? */
 
     /*
      * Do a soft reset of the chip so that everything is 
@@ -3016,20 +3013,23 @@
 		SIEN_SGE | SIEN_MA);
 
 #ifdef CONFIG_MVME16x
-    /* Enable scsi chip and s/w level 7 ints */
+    if (MACH_IS_MVME16x)
+    {
+        volatile unsigned long v;
 
-    v = *(volatile unsigned long *)0xfff40080;
-    v = (v & ~(0xf << 28)) | (4 << 28);
-    *(volatile unsigned long *)0xfff40080 = v;
-    v = *(volatile unsigned long *)0xfff4006c;
-    v |= 0x8000;
-    *(volatile unsigned long *)0xfff4006c = v;
-    v = *(volatile unsigned long *)0xfff4202c;
-    v = (v & ~0xff) | 0x10 | 4;
-    *(volatile unsigned long *)0xfff4202c = v;
-#else
-    /* Anything needed for your hardware */
+        /* Enable scsi chip and s/w level 7 ints */
+        v = *(volatile unsigned long *)0xfff40080;
+        v = (v & ~(0xf << 28)) | (4 << 28);
+        *(volatile unsigned long *)0xfff40080 = v;
+        v = *(volatile unsigned long *)0xfff4006c;
+        v |= 0x8000;
+        *(volatile unsigned long *)0xfff4006c = v;
+        v = *(volatile unsigned long *)0xfff4202c;
+        v = (v & ~0xff) | 0x10 | 4;
+        *(volatile unsigned long *)0xfff4202c = v;
+    }
 #endif
+    /* Anything needed for your hardware? */
     restore_flags(flags);
 }
 
@@ -3042,7 +3042,7 @@
  *
  * Side effects : If we haven't yet scheduled allocation of NCR53c7x0_cmd
  *	structures for this device, do so.  Attempt to complete all scheduled
- *	allocations using kmalloc(), putting NCR53c7x0_cmd structures on
+ *	allocations using get_free_page(), putting NCR53c7x0_cmd structures on
  *	the free list.  Teach programmers not to drink and hack.
  *
  * Inputs : cmd - SCSI command
@@ -3051,12 +3051,22 @@
  *	NULL on failure.
  */
 
+static void
+my_free_page (void *addr, int dummy)
+{
+    /* XXX This assumes default cache mode to be KERNELMAP_FULL_CACHING, which
+     * XXX may be invalid (CONFIG_060_WRITETHROUGH)
+     */
+    kernel_set_cachemode((u32)addr, 4096, KERNELMAP_FULL_CACHING);
+    free_page ((u32)addr);
+}
+
 static struct NCR53c7x0_cmd *
 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;
@@ -3094,28 +3104,31 @@
 	size += 256;
 #endif
 /* FIXME: for ISA bus '7xx chips, we need to or GFP_DMA in here */
-	real = kmalloc (size, GFP_ATOMIC);
-	if (!real) {
-	    if (hostdata->options & OPTION_DEBUG_ALLOCATION)
-		printk ("scsi%d : kmalloc(%d) failed\n",
-		    host->host_no, size);
-	    break;
-	}
+
+        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);
 	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 0
 	    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);
+	tmp->free = ((void (*)(void *, int)) my_free_page);
 	save_flags (flags);
 	cli();
 	tmp->next = hostdata->free;
@@ -3153,7 +3166,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;
@@ -3172,6 +3185,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,
@@ -3186,6 +3207,8 @@
     case READ_10:
     case READ_CAPACITY:
     case REQUEST_SENSE:
+    case READ_BLOCK_LIMITS:
+    case READ_TOC:
 	datain = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
     	dataout = 0;
 	break;
@@ -3213,13 +3236,17 @@
      * interrupt if a data phase is attempted on them.
      */
     case TEST_UNIT_READY:
+    case ALLOW_MEDIUM_REMOVAL:
     	datain = dataout = 0;
 	break;
     /*
      * We don't know about these commands, so generate code to handle
-     * both DATA IN and DATA OUT phases.
+     * both DATA IN and DATA OUT phases.  More efficient to identify them
+     * and add them to the above cases.
      */
     default:
+	printk("scsi%d : datain+dataout for command ", host->host_no);
+	print_command(cmd->cmnd);
 	datain = dataout = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
     }
 
@@ -3301,6 +3328,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) {
@@ -3362,7 +3393,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);
@@ -3380,13 +3411,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, 
@@ -3430,16 +3461,58 @@
  * 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 ? 
-	    virt_to_bus(((struct scatterlist *)cmd->buffer)[i].address) :
-	    virt_to_bus(cmd->request_buffer);
+	u32 vbuf = cmd->use_sg ? 
+	    (u32)(((struct scatterlist *)cmd->buffer)[i].address) :
+	    (u32)(cmd->request_buffer);
+	u32 bbuf = virt_to_bus((void *)vbuf);
 	u32 count = cmd->use_sg ?
 	    ((struct scatterlist *)cmd->buffer)[i].length :
 	    cmd->request_bufflen;
 
+	/*
+	 * 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 (((bbuf & 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 = vbuf;
+			bbuf = 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;
+	    	    }
+	    	    if (dataout)
+	    	    {
+			memcpy ((void *)tmp->bounce.buf, (void *)vbuf, count);
+			bbuf = virt_to_bus(tmp->bounce.buf);
+		    }
+	    }
+	}
+
 	if (datain) {
+            cache_clear(virt_to_phys((void *)vbuf), count);
 	    /* CALL other_in, WHEN NOT DATA_IN */  
 	    cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL | 
 		DCMD_TCI_IO) << 24) | 
@@ -3449,13 +3522,14 @@
 	    /* MOVE count, buf, WHEN DATA_IN */
 	    cmd_datain[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO) 
     	    	<< 24) | count;
-	    cmd_datain[3] = buf;
+	    cmd_datain[3] = bbuf;
 #if 0
 	    print_insn (host, cmd_datain, "dynamic ", 1);
 	    print_insn (host, cmd_datain + 2, "dynamic ", 1);
 #endif
 	}
 	if (dataout) {
+            cache_push(virt_to_phys((void *)vbuf), 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;
@@ -3464,7 +3538,7 @@
 	    /* MOVE count, buf, WHEN DATA+OUT */
 	    cmd_dataout[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I) << 24) 
 		| count;
-	    cmd_dataout[3] = buf;
+	    cmd_dataout[3] = bbuf;
 #if 0
 	    print_insn (host, cmd_dataout, "dynamic ", 1);
 	    print_insn (host, cmd_dataout + 2, "dynamic ", 1);
@@ -3534,7 +3608,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;
 
@@ -3712,9 +3786,6 @@
      * soon as it is idle.
      */
 
-    if (!MACH_IS_MVME16x)
-	flush_cache_all();
-
     if (hostdata->idle) {
 	hostdata->idle = 0;
 	hostdata->state = STATE_RUNNING;
@@ -3788,7 +3859,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) {
@@ -3860,7 +3931,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 ? */
@@ -4051,7 +4122,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++;
@@ -4070,20 +4141,6 @@
 }
 #endif
 
-/* Function : NCR53c7x0_intr
- *
- * Purpose : grab the global io_request_lock spin lock before entering the
- *      real interrupt routine.
- */
-static void
-do_NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) {
-    unsigned long flags;
-
-    spin_lock_irqsave(&io_request_lock, flags);
-    NCR53c7x0_intr(irq, dev_id, regs);
-    spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
 /*
  * Function : static void NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs)
  *
@@ -4103,7 +4160,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 */
@@ -4138,7 +4195,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;
@@ -4200,6 +4257,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);
@@ -4211,6 +4273,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;
@@ -4341,8 +4407,6 @@
 #endif
 		
 		hostdata->state = STATE_RUNNING;
-		if (!MACH_IS_MVME16x)
-		    flush_cache_all();
 		NCR53c7x0_write32 (DSP_REG, virt_to_bus(hostdata->dsp));
 		if (hostdata->options & OPTION_DEBUG_TRACE) {
 #ifdef CYCLIC_TRACE
@@ -4380,7 +4444,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;
@@ -4557,7 +4621,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;
@@ -4751,9 +4815,6 @@
 	print_insn (host, hostdata->dsp, "", 1);
     }
 #endif
-
-    if (!MACH_IS_MVME16x)
-	cache_push(virt_to_bus(hostdata->script), flushsize);
 }
 
 /*
@@ -4827,7 +4888,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);
     }
 }
@@ -4847,7 +4908,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 */
@@ -5098,7 +5159,7 @@
  * FIXME : (void *) cast in virt_to_bus should be unnecessary, because
  * 	it should take const void * as argument.
  */
-#ifndef CONFIG_MVME16x
+#if !defined(CONFIG_MVME16x) && !defined(CONFIG_BVME6000)
 	sprintf(buf, "%s0x%lx (virt 0x%p) : 0x%08x 0x%08x (virt 0x%p)", 
 	    (prefix ? prefix : ""), virt_to_bus((void *) insn), insn,  
 	    insn[0], insn[1], bus_to_virt (insn[1]));
@@ -5106,12 +5167,12 @@
 	/* 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);
 	if ((dcmd & DCMD_TYPE_MASK) == DCMD_TYPE_MMI)  {
-#ifndef CONFIG_MVME16x
+#if !defined(CONFIG_MVME16x) && !defined(CONFIG_BVME6000)
 	    sprintf (tmp, " 0x%08x (virt 0x%p)\n", insn[2], 
 		bus_to_virt(insn[2]));
 #else
@@ -5153,7 +5214,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;
@@ -5244,7 +5305,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;
@@ -5275,13 +5337,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
@@ -5334,7 +5397,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);
@@ -5403,7 +5466,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;
@@ -5472,6 +5535,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) 
@@ -5509,7 +5582,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;
@@ -5551,6 +5624,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);
@@ -5583,7 +5657,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;
@@ -5666,7 +5740,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;
@@ -5688,7 +5762,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,
@@ -5705,8 +5779,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)
@@ -5741,7 +5816,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();
@@ -5782,7 +5857,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();
@@ -5817,7 +5892,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;
@@ -5883,7 +5958,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);
@@ -5922,7 +5997,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);
 
@@ -6000,7 +6075,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;
@@ -6064,7 +6139,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)
@@ -6098,6 +6173,12 @@
 	    host->host_no, hostdata->num_cmds);
     if (hostdata->events) 
 	vfree ((void *)hostdata->events);
+
+    /* XXX This assumes default cache mode to be KERNELMAP_FULL_CACHING, which
+     * XXX may be invalid (CONFIG_060_WRITETHROUGH)
+     */
+    kernel_set_cachemode((u32)hostdata, 8192, KERNELMAP_FULL_CACHING);
+    free_pages ((u32)hostdata, 1);
     return 1;
 }
 Scsi_Host_Template driver_template = NCR53c7xx;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov