## Automatically generated incremental diff
## From:   linux-2.0.31-pre5
## To:     linux-2.0.31-pre6
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.0.31-pre5/arch/alpha/kernel/traps.c linux-2.0.31-pre6/arch/alpha/kernel/traps.c
--- linux-2.0.31-pre5/arch/alpha/kernel/traps.c	1997-02-02 05:00:20.000000000 -0800
+++ linux-2.0.31-pre6/arch/alpha/kernel/traps.c	2003-08-15 15:04:01.000000000 -0700
@@ -420,7 +420,7 @@
 			  unsigned long a3, unsigned long a4, unsigned long a5,
 			  struct pt_regs regs)
 {
-	if (regs.r0 != 112)
+	if (regs.r0 != 112 && regs.r0 < 300)
 		printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);
 	return -1;
 }
diff -urN linux-2.0.31-pre5/CREDITS linux-2.0.31-pre6/CREDITS
--- linux-2.0.31-pre5/CREDITS	2003-08-15 15:04:00.000000000 -0700
+++ linux-2.0.31-pre6/CREDITS	2003-08-15 15:04:01.000000000 -0700
@@ -413,7 +413,7 @@
 S: Australia
 
 N: Ralf Flaxa
-E: rfflaxa@immd4.informatik.uni-erlangen.de
+E: rf@lst.de
 D: The Linux Support Team Erlangen
 D: Creator of LST distribution
 D: Author of installation tool LISA
diff -urN linux-2.0.31-pre5/Documentation/Configure.help linux-2.0.31-pre6/Documentation/Configure.help
--- linux-2.0.31-pre5/Documentation/Configure.help	2003-08-15 15:04:00.000000000 -0700
+++ linux-2.0.31-pre6/Documentation/Configure.help	2003-08-15 15:04:01.000000000 -0700
@@ -472,7 +472,10 @@
   the same end. SYN cookies use less space than RST cookies,
   but have a small probability of introducing an non timed-out
   failure to connect in the remote TCP. You can use both options
-  simultatenously.
+  simultatenously.  If you are SYN flooded, the source address
+  reported by the kernel is likely to have been forged by the attacker.
+  The source address is reported as an aid in tracing the packets to 
+  their actual source.  
 
 SYN flood protection
 CONFIG_RST_COOKIES
@@ -486,7 +489,10 @@
   The SYN_COOKIES option provides an alternative method to accomplish
   the same end. RST cookies use more space than SYN cookies on your
   machine, but never increase the probability of a frozen connection
-  in a remote TCP. You can use both options simultatenously.
+  in a remote TCP. You can use both options simultatenously.  If you 
+  are SYN flooded, the source address reported by the kernel is likely 
+  to have been forged by the attacker.  The source address is reported 
+  as an aid in tracing the packets to their actual source.  
 
 Sun floppy controller support
 CONFIG_BLK_DEV_SUNFD
@@ -1554,24 +1560,41 @@
   of PCI-SCSI controllers. This driver supports parity checking,
   tagged command queuing, fast scsi II transfer up to 10 MB/s with
   narrow scsi devices and 20 MB/s with wide scsi devices.
-  This driver has been tested OK with linux/i386 and is currently
-  untested under linux/Alpha. If you intend to use this driver under
-  linux/Alpha, just try it first with read-only or mounted read-only
-  devices.  Memory mapped io is currently not supported under
-  linux/Alpha. Please read drivers/scsi/README.ncr53c8xx for more
-  information. 
+  Support of Ultra SCSI data transfers with NCR53C860 and NCR53C875 
+  controllers has been recently added to the driver.
+  Please read drivers/scsi/README.ncr53c8xx for more information.
+  Linux/i386 and Linux/Alpha are supported by this driver.
+
+synchronous data transfers frequency
+CONFIG_SCSI_NCR53C8XX_SYNC
+  SCSI-2 specifications allow scsi devices to negotiate a synchronous 
+  transfer period of 25 nano-seconds or more.
+  The transfer period value is 4 times the agreed transfer period.
+  So, data can be transferred at a 10 MHz frequency, allowing 10
+  MB/second throughput with 8 bits scsi-2 devices and 20 MB/second
+  with wide16 devices.  This frequency can be used safely with
+  differential devices but may cause problems with singled-ended
+  devices.
+  Specify 0 if you want to only use asynchronous data transfers.
+  Otherwise, specify a value between 5 and 10.  Commercial O/Ses
+  generally use 5 Mhz frequency for synchronous transfers.  It is a
+  reasonable default value.
+  However, a flawless singled-ended scsi bus supports 10 MHz data
+  transfers.  Regardless the value chosen in the Linux configuration,
+  the synchronous period can be changed after boot-up through the
+  /proc/scsi file system. The generic command is:
+      echo "setsync #target period" >/proc/scsi/ncr53c8xx/0
+  Use a 25 ns period for 10 Mhz synchronous data transfers.
+  If you don't know what to do now, go with the default.
 
-force normal IO
+use normal IO
 CONFIG_SCSI_NCR53C8XX_IOMAPPED
-  Under linux/Alpha only normal io is currently supported.
-  Under linux/i386, this option allows you to force the driver to use
-  normal IO.  Memory mapped IO has less latency than normal IO.
-  During the initialization phase, the driver first tries to use
-  memory mapped io.  If nothing seems wrong, it will use memory mapped
-  io.  If a flaw is detected, it will use normal io.  However, it's
-  possible that memory mapped does not work properly for you and the
-  driver has not detected the problem; then you would want to say Y
-  here.  The normal answer therefore is N.
+  This option allows you to force the driver to use normal IO.
+  Memory mapped IO has less latency than normal IO and works for most 
+  Intel-based hardware.
+  Under Linux/Alpha only normal IO is currently supported by the driver 
+  and so, this option has no effect.
+  The normal answer therefore is N.
 
 not allow targets to disconnect
 CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
@@ -1596,36 +1619,51 @@
   The safe answer therefore is N.
   The normal answer therefore is Y.
 
-force asynchronous transfer mode
-CONFIG_SCSI_NCR53C8XX_FORCE_ASYNCHRONOUS
-  This option allows you to force asynchronous transfer mode for all
-  devices at linux startup. You can enable synchronous negotiation
-  with the "setsync" control command after boot-up, for example:
-     echo "setsync 2 25" >/proc/scsi/ncr53c8xx/0
-  asks the driver to set the period to 25 ns (10MB/sec) for target 2
-  of controller 0 (please read drivers/scsi/README.ncr53c8xx for more
-  information). The safe answer therefore is Y.  The normal answer
-  therefore is N.
- 
-force synchronous negotiation
-CONFIG_SCSI_NCR53C8XX_FORCE_SYNC_NEGO
-  Some scsi-2 devices support synchronous negotiations but do not
-  report this feature in byte 7 of inquiry data.
-  Answer Y only if you suspect some device to be so humble.
-  The normal answer therefore is N.
- 
-disable master parity checking
-CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK
-  Some hardware may have problems with parity during master cycles on
-  PCI bus.  Only seen once. Answer Y if you suspect such problem.  The
-  normal answer therefore is N.
-
-disable scsi parity checking
-CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK
-  Parity on scsi bus is a system option. If one device checks parity,
-  then all devices on the scsi bus must generate parity.  However, the
-  parity can be ignored by the scsi devices.  Answer Y only if you
-  know what you are doing.  The normal answer therefore is N.
+maximum number of queued commands
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS
+  This option allows you to specify the maximum number of commands
+  that can be queued to a device, when tagged command queuing is
+  possible.  The default value is 4. Minimum is 2, maximum is 12.  The
+  normal answer therefore is the default one.
+
+detect and read serial NVRAM
+CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT
+  Enable support for reading the serial NVRAM data on Symbios and
+  some Symbios compatible cards, and Tekram DC390W/U/F cards. Useful for
+  systems with more than one Symbios compatible controller where at least
+  one has a serial NVRAM, or for a system with a mixture of Symbios and
+  Tekram cards. Enables setting the boot order of host adaptors
+  to something other than the default order or "reverse probe" order. 
+  Also enables Symbios and Tekram cards to be distinguished so
+  CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT may be set in a system with a
+  mixture of Symbios and Tekram cards so the Symbios cards can make use of
+  the full range of Symbios features, differential, led pin, without
+  causing problems for the Tekram card(s).
+      (added by Richard Waltham: dormouse@farsrobt.demon.co.uk)
+  Also enables setting host and targets SCSI features as defined in the 
+  user setup for each host using a serial NVRAM (added by the maintainer).
+  The default answer is N, the normal answer should be Y.
+  Read drivers/scsi/README.ncr53c8xx for more information.
+
+assume boards are SYMBIOS compatible
+CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
+  This option allows you to enable some features depending on GPIO
+  wiring.  These General Purpose Input/Output pins can be used for
+  vendor specific features or implementation of the standard SYMBIOS
+  features.  Genuine SYMBIOS boards use GPIO0 in output for controller
+  LED and GPIO3 bit as a flag indicating singled-ended/differential
+  interface.
+  If all the boards of your system are genuine SYMBIOS boards or use
+  BIOS and drivers from SYMBIOS, you would want to enable this option.
+  The driver behaves correctly on my system with this option enabled.
+  (SDMS 4.0 + Promise SCSI ULTRA 875 rev 0x3 + ASUS SC200 810A rev
+  0x12).  This option must be set to N if your system has at least one
+  53C8XX based scsi board with a vendor-specific BIOS (example: Tekram
+  DC-390/U/W/F).  If unsure, say N.
+  However, if all your non Symbios compatible boards have NvRAM, setting 
+  option CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT allows the driver to 
+  distinguish Symbios compatible boards from other ones.
+  So, you can answer Y if all non Symbios compatible boards have NVRAM.
 
 Always IN2000 SCSI support
 CONFIG_SCSI_IN2000
@@ -1742,6 +1780,13 @@
   and removed from the running kernel whenever you want), say M here
   and read Documentation/modules.txt.
 
+Tekram DC390(T) (AMD PCscsi) SCSI support
+CONFIG_SCSI_DC390T
+  This driver supports the Tekram DC390(T) PCI SCSI Hostadapter with
+  the Am53C974A chip, and perhaps other cards using the same chip.
+  This driver does _not_ support the DC390W/U/F adaptor with the 
+  NCR/Symbios chips.
+
 AM53/79C974 PCI SCSI support
 CONFIG_SCSI_AM53C974
   This is support for the AM53/79C974 SCSI host adapters. Please read
@@ -2397,6 +2442,12 @@
   FMV-184 and it is not working, you may need to disable Plug & Play
   mode of the card.
 
+Intel EtherExpress/Pro 100B support'
+CONFIG_EEXPRESS_PRO100B
+  If you have an Intel EtherExpress Pro 100 10/100Mbps PCI Ethernet
+  card, answer yes.  As of kernel release 2.0.31 this driver was
+  still experimental.
+
 EtherExpressPro support
 CONFIG_EEXPRESS_PRO
   If you have a network (ethernet) card of this type, say Y and read
diff -urN linux-2.0.31-pre5/drivers/char/random.c linux-2.0.31-pre6/drivers/char/random.c
--- linux-2.0.31-pre5/drivers/char/random.c	2003-08-15 15:04:00.000000000 -0700
+++ linux-2.0.31-pre6/drivers/char/random.c	2003-08-15 15:04:01.000000000 -0700
@@ -1337,8 +1337,13 @@
 	do_gettimeofday(&tv);
 	seq = tmp[1] + tv.tv_usec+tv.tv_sec*1000000;
 #if 0
-	printk("init_seq(%lx, %lx, %d, %d) = %d\n",
-	       saddr, daddr, sport, dport, seq);
+	/*
+	  ugh...we can only use in_ntoa once per printk, splitting
+	  a single line of info into multiple printk's confuses klogd,
+	  and Linus says in_ntoa sucks anyway :)
+	*/
+	printk("init_seq(%d.%d.%d.%d:%d, %d.%d.%d.%d:%d) = %d\n",
+		NIPQUAD(saddr), sport, NIPQUAD(daddr), dport, seq);
 #endif
 	return (seq);
 }
@@ -1361,7 +1366,7 @@
 
 	/*
 	 * Pick a random secret the first time we open a TCP
-	 * connection, and expire secretes older than 5 minutes.
+	 * connection, and expire secrets older than 5 minutes.
 	 */
 	if (is_init == 0 || jiffies-secret_timestamp[offset] > 600*HZ) {
 		if (is_init == 0) valid_secret[0] = valid_secret[1] = 0;
@@ -1386,14 +1391,14 @@
 	if (!validate) {
 		if (seq == sseq) seq++;
 #if 0
-		printk("init_seq(%lx, %lx, %d, %d, %d) = %d\n",
-		       saddr, daddr, sport, dport, sseq, seq);
+		printk("init_seq(%d.%d.%d.%d:%d %d.%d.%d.%d:%d, %d) = %d\n",
+			NIPQUAD(saddr), sport, NIPQUAD(daddr), dport, sseq, seq);
 #endif
 		return (seq);
 	} else {
 		if (seq == sseq || (seq+1) == sseq) {
-			printk("validated probe(%lx, %lx, %d, %d, %d)\n",
-		       		saddr, daddr, sport, dport, sseq);
+			printk("validated probe(%d.%d.%d.%d:%d, %d.%d.%d.%d:%d, %d)\n",
+				NIPQUAD(saddr), sport, NIPQUAD(daddr), dport, sseq);
 			return 1;
 		}
 		if (jiffies-secret_timestamp[(offset+1)%2] <= 1200*HZ) {
@@ -1405,15 +1410,15 @@
 			seq = tmp[1];
 			if (seq == sseq || (seq+1) == sseq) {
 #ifdef 0
-				printk("validated probe(%lx, %lx, %d, %d, %d)\n",
-		       			saddr, daddr, sport, dport, sseq);
+				printk("validated probe(%d.%d.%d.%d:%d, %d.%d.%d.%d:%d, %d)\n",
+					NIPQUAD(saddr), sport, NIPQUAD(daddr), dport, sseq);
 #endif
 				return 1;
 			}
 		}
 #ifdef 0
-		printk("failed validation on probe(%lx, %lx, %d, %d, %d)\n",
-			saddr, daddr, sport, dport, sseq);
+		printk("failed validation on probe(%d.%d.%d.%d:%d, %d.%d.%d.%d:%d, %d)\n",
+			NIPQUAD(saddr), sport, NIPQUAD(daddr), dport, sseq);
 #endif
 		return 0;
 	}
diff -urN linux-2.0.31-pre5/drivers/char/tty_io.c linux-2.0.31-pre6/drivers/char/tty_io.c
--- linux-2.0.31-pre5/drivers/char/tty_io.c	2003-08-15 15:04:00.000000000 -0700
+++ linux-2.0.31-pre6/drivers/char/tty_io.c	2003-08-15 15:04:01.000000000 -0700
@@ -11,7 +11,7 @@
  * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
  *
  * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the
- * tty_struct and tty_queue structures.  Previously there was a array
+ * tty_struct and tty_queue structures.  Previously there was an array
  * of 256 tty_struct's which was statically allocated, and the
  * tty_queue structures were allocated at boot time.  Both are now
  * dynamically allocated only when the tty is open.
@@ -44,6 +44,9 @@
  * 
  * Restrict vt switching via ioctl()
  *      -- grif@cs.ucr.edu, 5-Dec-95
+ *
+ * Rewrote init_dev and release_dev to eliminate races.
+ *	-- Bill Hawes <whawes@star.net>, June 97
  */
 
 #include <linux/config.h>
@@ -830,14 +833,27 @@
 		(unsigned int)count);
 }
 
+/* Semaphore to protect creating and releasing a tty */
+static struct semaphore tty_sem = MUTEX;
+static void down_tty_sem(int index)
+{
+	down(&tty_sem);
+}
+static void up_tty_sem(int index)
+{
+	up(&tty_sem);
+}
+static void release_mem(struct tty_struct *tty, int idx);
+
 /*
- * This is so ripe with races that you should *really* not touch this
- * unless you know exactly what you are doing. All the changes have to be
- * made atomically, or there may be incorrect pointers all over the place.
+ * Rewritten to remove races and properly clean up after a failed open.  
+ * The new code protects the open with a semaphore, so it's really 
+ * quite straightforward.  The semaphore locking can probably be
+ * relaxed for the (most common) case of reopening a tty.
  */
 static int init_dev(kdev_t device, struct tty_struct **ret_tty)
 {
-	struct tty_struct *tty, **tty_loc, *o_tty, **o_tty_loc;
+	struct tty_struct *tty, *o_tty;
 	struct termios *tp, **tp_loc, *o_tp, **o_tp_loc;
 	struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
 	struct tty_driver *driver;	
@@ -849,163 +865,221 @@
 		return -ENODEV;
 
 	idx = MINOR(device) - driver->minor_start;
-	tty = o_tty = NULL;
+
+	/* 
+	 * Check whether we need to acquire the tty semaphore to avoid
+	 * race conditions.  For now, play it safe.
+	 */
+	down_tty_sem(idx);
+
+	/* check whether we're reopening an existing tty */
+	tty = driver->table[idx];
+	if(tty) goto fast_track;
+
+	/*
+	 * First time open is complex, especially for PTY devices.
+	 * This code guarantees that either everything succeeds and the
+	 * TTY is ready for operation, or else the table slots are vacated
+	 * and the allocated memory released.  (Except that the termios 
+	 * and locked termios may be retained.)
+	 */
+
+	o_tty = NULL;
 	tp = o_tp = NULL;
 	ltp = o_ltp = NULL;
-	o_tty_loc = NULL;
-	o_tp_loc = o_ltp_loc = NULL;
 
-	tty_loc = &driver->table[idx];
-	tp_loc = &driver->termios[idx];
-	ltp_loc = &driver->termios_locked[idx];
+	tty = (struct tty_struct*) get_free_page(GFP_KERNEL);
+	if(!tty)
+		goto fail_no_mem;
+	initialize_tty_struct(tty);
+	tty->device = device;
+	tty->driver = *driver;
 
-repeat:
-	retval = -EIO;
-	if (driver->type == TTY_DRIVER_TYPE_PTY &&
-	    driver->subtype == PTY_TYPE_MASTER &&
-	    *tty_loc && (*tty_loc)->count)
-		goto end_init;
-	retval = -ENOMEM;
-	if (!*tty_loc && !tty) {
-		if (!(tty = (struct tty_struct*) get_free_page(GFP_KERNEL)))
-			goto end_init;
-		initialize_tty_struct(tty);
-		tty->device = device;
-		tty->driver = *driver;
-		goto repeat;
-	}
-	if (!*tp_loc && !tp) {
+	tp_loc = &driver->termios[idx];
+	if (!*tp_loc) {
 		tp = (struct termios *) kmalloc(sizeof(struct termios),
 						GFP_KERNEL);
 		if (!tp)
-			goto end_init;
+			goto free_mem_out;
 		*tp = driver->init_termios;
-		goto repeat;
 	}
-	if (!*ltp_loc && !ltp) {
+
+	ltp_loc = &driver->termios_locked[idx];
+	if (!*ltp_loc) {
 		ltp = (struct termios *) kmalloc(sizeof(struct termios),
 						 GFP_KERNEL);
 		if (!ltp)
-			goto end_init;
+			goto free_mem_out;
 		memset(ltp, 0, sizeof(struct termios));
-		goto repeat;
 	}
+
 	if (driver->type == TTY_DRIVER_TYPE_PTY) {
-		o_tty_loc = &driver->other->table[idx];
-		o_tp_loc = &driver->other->termios[idx];
-		o_ltp_loc = &driver->other->termios_locked[idx];
+		o_tty = (struct tty_struct *) get_free_page(GFP_KERNEL);
+		if (!o_tty)
+			goto free_mem_out;
+		initialize_tty_struct(o_tty);
+		o_tty->device = (kdev_t) MKDEV(driver->other->major,
+					driver->other->minor_start + idx);
+		o_tty->driver = *driver->other;
 
-		if (!*o_tty_loc && !o_tty) {
-			kdev_t 	o_device;
-			
-			o_tty = (struct tty_struct *)
-				get_free_page(GFP_KERNEL);
-			if (!o_tty)
-				goto end_init;
-			o_device = MKDEV(driver->other->major,
-					 driver->other->minor_start + idx);
-			initialize_tty_struct(o_tty);
-			o_tty->device = o_device;
-			o_tty->driver = *driver->other;
-			goto repeat;
-		}
-		if (!*o_tp_loc && !o_tp) {
+		o_tp_loc  = &driver->other->termios[idx];
+		if (!*o_tp_loc) {
 			o_tp = (struct termios *)
 				kmalloc(sizeof(struct termios), GFP_KERNEL);
 			if (!o_tp)
-				goto end_init;
+				goto free_mem_out;
 			*o_tp = driver->other->init_termios;
-			goto repeat;
 		}
-		if (!*o_ltp_loc && !o_ltp) {
+
+		o_ltp_loc = &driver->other->termios_locked[idx];
+		if (!*o_ltp_loc) {
 			o_ltp = (struct termios *)
 				kmalloc(sizeof(struct termios), GFP_KERNEL);
 			if (!o_ltp)
-				goto end_init;
+				goto free_mem_out;
 			memset(o_ltp, 0, sizeof(struct termios));
-			goto repeat;
 		}
-		
+
+		/*
+		 * Everything allocated ... set up the o_tty structure.
+		 */
+		driver->other->table[idx] = o_tty;
+		if (!*o_tp_loc)
+			*o_tp_loc = o_tp;
+		if (!*o_ltp_loc)
+			*o_ltp_loc = o_ltp;
+		o_tty->termios = *o_tp_loc;
+		o_tty->termios_locked = *o_ltp_loc;
+		(*driver->other->refcount)++;
+		if (driver->subtype == PTY_TYPE_MASTER)
+			o_tty->count++;
+
+		/* Establish the links in both directions */
+		tty->link   = o_tty;
+		o_tty->link = tty;
 	}
-	/* Now we have allocated all the structures: update all the pointers.. */
-	if (!*tp_loc) {
+
+	/* 
+	 * All structures have been allocated, so now we install them.
+	 * Failures after this point use release_mem to clean up, so 
+	 * there's no need to null out the local pointers.
+	 */
+	driver->table[idx] = tty;
+	if (!*tp_loc)
 		*tp_loc = tp;
-		tp = NULL;
-	}
-	if (!*ltp_loc) {
+	if (!*ltp_loc)
 		*ltp_loc = ltp;
-		ltp = NULL;
+	tty->termios = *tp_loc;
+	tty->termios_locked = *ltp_loc;
+	(*driver->refcount)++;
+	tty->count++;
+
+	/* 
+	 * Structures all installed ... call the ldisc open routines.
+	 * If we fail here just call release_mem to clean up.  No need
+	 * to decrement the use counts, as release_mem doesn't care.
+	 */
+	if (tty->ldisc.open) {
+		retval = (tty->ldisc.open)(tty);
+		if (retval)
+			goto release_mem_out;
 	}
-	if (!*tty_loc) {
-		tty->termios = *tp_loc;
-		tty->termios_locked = *ltp_loc;
-		*tty_loc = tty;
-		(*driver->refcount)++;
-		(*tty_loc)->count++;
-		if (tty->ldisc.open) {
-			retval = (tty->ldisc.open)(tty);
-			if (retval < 0) {
-				(*tty_loc)->count--;
-				tty = NULL;
-				goto end_init;
-			}
+	if (o_tty && o_tty->ldisc.open) {
+		retval = (o_tty->ldisc.open)(o_tty);
+		if (retval) {
+			if (tty->ldisc.close)
+				(tty->ldisc.close)(tty);
+			goto release_mem_out;
 		}
-		tty = NULL;
-	} else {
-		if ((*tty_loc)->flags & (1 << TTY_CLOSING)) {
-			printk("Attempt to open closing tty %s.\n",
-			       tty_name(*tty_loc));
-			printk("Ack!!!!  This should never happen!!\n");
-			return -EINVAL;
-		}
-		(*tty_loc)->count++;
 	}
-	if (driver->type == TTY_DRIVER_TYPE_PTY) {
-		if (!*o_tp_loc) {
-			*o_tp_loc = o_tp;
-			o_tp = NULL;
-		}
-		if (!*o_ltp_loc) {
-			*o_ltp_loc = o_ltp;
-			o_ltp = NULL;
-		}
-		if (!*o_tty_loc) {
-			o_tty->termios = *o_tp_loc;
-			o_tty->termios_locked = *o_ltp_loc;
-			*o_tty_loc = o_tty;
-			(*driver->other->refcount)++;
-			if (o_tty->ldisc.open) {
-				retval = (o_tty->ldisc.open)(o_tty);
-				if (retval < 0) {
-					(*tty_loc)->count--;
-					o_tty = NULL;
-					goto end_init;
-				}
-			}
-			o_tty = NULL;
-		}
-		(*tty_loc)->link = *o_tty_loc;
-		(*o_tty_loc)->link = *tty_loc;
-		if (driver->subtype == PTY_TYPE_MASTER)
-			(*o_tty_loc)->count++;
+	goto success;
+
+	/*
+	 * This fast open can be used if the tty is already open.
+	 * No memory is allocated, and the only failures are from
+	 * attempting to open a closing tty or attempting multiple
+	 * opens on a pty master.
+	 */
+fast_track:
+	retval = -EIO;
+	if (test_bit(TTY_CLOSING, &tty->flags))
+		goto end_init;
+
+	if (driver->type == TTY_DRIVER_TYPE_PTY &&
+	    driver->subtype == PTY_TYPE_MASTER) {
+		/*
+		 * special case for PTY masters: only one open permitted, 
+		 * and the slave side open count is incremented as well.
+		 */
+		if (tty->count)
+			goto end_init;
+		tty->link->count++;
 	}
-	(*tty_loc)->driver = *driver;
-	*ret_tty = *tty_loc;
+	tty->count++;
+	tty->driver = *driver; /* N.B. why do this every time?? */
+
+success:
 	retval = 0;
+	*ret_tty = tty;
+	
+	/* All paths come through here to release the semaphore */
 end_init:
-	if (tty)
-		free_page((unsigned long) tty);
-	if (o_tty)
-		free_page((unsigned long) o_tty);
-	if (tp)
-		kfree_s(tp, sizeof(struct termios));
+	up_tty_sem(idx);
+	return retval;
+
+	/* Release locally allocated memory ... nothing placed in slots */
+free_mem_out:
 	if (o_tp)
 		kfree_s(o_tp, sizeof(struct termios));
+	if (o_tty)
+		free_page((unsigned long) o_tty);
 	if (ltp)
 		kfree_s(ltp, sizeof(struct termios));
-	if (o_ltp)
-		kfree_s(o_ltp, sizeof(struct termios));
-	return retval;
+	if (tp)
+		kfree_s(tp, sizeof(struct termios));
+	free_page((unsigned long) tty);
+
+fail_no_mem:
+	retval = -ENOMEM;
+	goto end_init;
+
+	/* call the tty release_mem routine to clean out this slot */
+release_mem_out:
+	printk("init_dev: ldisc open failed, clearing slot %d\n", idx);
+	release_mem(tty, idx);
+	goto end_init;
+}
+
+/*
+ * Releases memory associated with a tty structure, and clears out the
+ * driver table slots.
+ */
+static void release_mem(struct tty_struct *tty, int idx)
+{
+	struct tty_struct *o_tty;
+	struct termios *tp;
+
+	if ((o_tty = tty->link) != NULL) {
+		o_tty->driver.table[idx] = NULL;
+		if (o_tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) {
+			tp = o_tty->driver.termios[idx];
+			o_tty->driver.termios[idx] = NULL;
+			kfree_s(tp, sizeof(struct termios));
+		}
+		o_tty->magic = 0;
+		(*o_tty->driver.refcount)--;
+		free_page((unsigned long) o_tty);
+	}
+
+	tty->driver.table[idx] = NULL;
+	if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) {
+		tp = tty->driver.termios[idx];
+		tty->driver.termios[idx] = NULL;
+		kfree_s(tp, sizeof(struct termios));
+	}
+	tty->magic = 0;
+	(*tty->driver.refcount)--;
+	free_page((unsigned long) tty);
 }
 
 /*
@@ -1016,8 +1090,7 @@
 static void release_dev(struct file * filp)
 {
 	struct tty_struct *tty, *o_tty;
-	struct termios *tp, *o_tp, *ltp, *o_ltp;
-	struct task_struct **p;
+	int	pty_master, tty_closing, o_tty_closing, do_sleep;
 	int	idx;
 	
 	tty = (struct tty_struct *)filp->private_data;
@@ -1028,10 +1101,11 @@
 
 	tty_fasync(filp->f_inode, filp, 0);
 
-	tp = tty->termios;
-	ltp = tty->termios_locked;
-
 	idx = MINOR(tty->device) - tty->driver.minor_start;
+	pty_master = (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
+		      tty->driver.subtype == PTY_TYPE_MASTER);
+	o_tty = tty->link;
+
 #ifdef TTY_PARANOIA_CHECK
 	if (idx < 0 || idx >= tty->driver.num) {
 		printk("release_dev: bad idx when trying to free (%s)\n",
@@ -1043,15 +1117,15 @@
 		       idx, kdevname(tty->device));
 		return;
 	}
-	if (tp != tty->driver.termios[idx]) {
-		printk("release_dev: driver.termios[%d] not termios for ("
-		       "%s)\n",
+	if (tty->termios != tty->driver.termios[idx]) {
+		printk("release_dev: driver.termios[%d] not termios "
+		       "for (%s)\n",
 		       idx, kdevname(tty->device));
 		return;
 	}
-	if (ltp != tty->driver.termios_locked[idx]) {
-		printk("release_dev: driver.termios_locked[%d] not termios_locked for ("
-		       "%s)\n",
+	if (tty->termios_locked != tty->driver.termios_locked[idx]) {
+		printk("release_dev: driver.termios_locked[%d] not "
+		       "termios_locked for (%s)\n",
 		       idx, kdevname(tty->device));
 		return;
 	}
@@ -1062,10 +1136,6 @@
 	       tty->count);
 #endif
 
-	o_tty = tty->link;
-	o_tp = (o_tty) ? o_tty->termios : NULL;
-	o_ltp = (o_tty) ? o_tty->termios_locked : NULL;
-
 #ifdef TTY_PARANOIA_CHECK
 	if (tty->driver.other) {
 		if (o_tty != tty->driver.other->table[idx]) {
@@ -1074,34 +1144,90 @@
 			       idx, kdevname(tty->device));
 			return;
 		}
-		if (o_tp != tty->driver.other->termios[idx]) {
-			printk("release_dev: other->termios[%d] not o_termios for ("
-			       "%s)\n",
+		if (o_tty->termios != tty->driver.other->termios[idx]) {
+			printk("release_dev: other->termios[%d] not o_termios "
+			       "for (%s)\n",
 			       idx, kdevname(tty->device));
 			return;
 		}
-		if (o_ltp != tty->driver.other->termios_locked[idx]) {
-			printk("release_dev: other->termios_locked[%d] not o_termios_locked for ("
-			       "%s)\n",
+		if (o_tty->termios_locked != 
+		      tty->driver.other->termios_locked[idx]) {
+			printk("release_dev: other->termios_locked[%d] not "
+			       "o_termios_locked for (%s)\n",
 			       idx, kdevname(tty->device));
 			return;
 		}
-
 		if (o_tty->link != tty) {
 			printk("release_dev: bad pty pointers\n");
 			return;
 		}
 	}
 #endif
-	
+	/*
+	 * Sanity check: if tty->count is going to zero, there shouldn't be
+	 * any waiters on tty->read_wait or tty->write_wait.  We test the
+	 * wait queues and kick everyone out _before_ actually starting to
+	 * close.  This ensures that we won't block while releasing the tty
+	 * structure.
+	 *
+	 * The test for the o_tty closing is necessary, since the master and
+	 * slave sides may close in any order.  If the slave side closes out
+	 * first, its count will be one, since the master side holds an open.
+	 * Thus this test wouldn't be triggered at the time the slave closes,
+	 * so we do it now.
+	 *
+	 * Note that it's possible for the tty to be opened again while we're
+	 * flushing out waiters.  By recalculating the closing flags before
+	 * each iteration we avoid any problems.
+	 */
+	while (1) {
+		tty_closing = tty->count <= 1;
+		o_tty_closing = o_tty &&
+			(o_tty->count <= (pty_master ? 1 : 0));
+		do_sleep = 0;
+
+		if (tty_closing) {
+			if (waitqueue_active(&tty->read_wait)) {
+				wake_up(&tty->read_wait);
+				do_sleep++;
+			}
+			if (waitqueue_active(&tty->write_wait)) {
+				wake_up(&tty->write_wait);
+				do_sleep++;
+			}
+		}
+		if (o_tty_closing) {
+			if (waitqueue_active(&o_tty->read_wait)) {
+				wake_up(&o_tty->read_wait);
+				do_sleep++;
+			}
+			if (waitqueue_active(&o_tty->write_wait)) {
+				wake_up(&o_tty->write_wait);
+				do_sleep++;
+			}
+		}
+		if (!do_sleep)
+			break;
+
+		printk("release_dev: %s: read/write wait queue active!\n",
+		       tty_name(tty));
+		schedule();
+	}	
+
+	/*
+	 * The closing flags are now consistent with the open counts on 
+	 * both sides, and we've completed the last operation that could 
+	 * block, so it's safe to proceed with closing.
+	 */
+
 	if (tty->driver.close)
 		tty->driver.close(tty, filp);
-	if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
-	    tty->driver.subtype == PTY_TYPE_MASTER) {
-		if (--tty->link->count < 0) {
+
+	if (pty_master) {
+		if (--o_tty->count < 0) {
 			printk("release_dev: bad pty slave count (%d) for %s\n",
-			       tty->count, tty_name(tty));
-			tty->link->count = 0;
+			       o_tty->count, tty_name(o_tty));
+			o_tty->count = 0;
 		}
 	}
 	if (--tty->count < 0) {
@@ -1109,41 +1235,48 @@
 		       tty->count, tty_name(tty));
 		tty->count = 0;
 	}
-	if (tty->count)
-		return;
 
 	/*
-	 * We're committed; at this point, we must not block!
+	 * Perform some housekeeping before deciding whether to return.
+	 *
+	 * Set the TTY_CLOSING flag if this was the last open.  In the
+	 * case of a pty we may have to wait around for the other side
+	 * to close, and TTY_CLOSING makes sure we can't be reopened.
 	 */
-	if (o_tty) {
-		if (o_tty->count)
-			return;
-		tty->driver.other->table[idx] = NULL;
-		tty->driver.other->termios[idx] = NULL;
-		kfree_s(o_tp, sizeof(struct termios));
+	if(tty_closing)
+		set_bit(TTY_CLOSING, &tty->flags);
+	if(o_tty_closing)
+		set_bit(TTY_CLOSING, &o_tty->flags);
+
+	/*
+	 * If _either_ side is closing, make sure there aren't any
+	 * processes that still think tty or o_tty is their controlling
+	 * tty.  Also, clear redirect if it points to either tty.
+	 */
+	if (tty_closing || o_tty_closing) {
+		struct task_struct *p;
+
+		for_each_task(p) {
+			if (p->tty == tty || (o_tty && p->tty == o_tty))
+				p->tty = NULL;
+		}
+
+		if (redirect == tty || (o_tty && redirect == o_tty))
+			redirect = NULL;
 	}
+
+	/* check whether both sides are closing ... */
+	if (!tty_closing || (o_tty && !o_tty_closing))
+		return;
+	filp->private_data = 0;
 	
 #ifdef TTY_DEBUG_HANGUP
 	printk("freeing tty structure...");
 #endif
-	tty->flags |= (1 << TTY_CLOSING);
-
-	/*
-	 * Make sure there aren't any processes that still think this
-	 * tty is their controlling tty.
-	 */
-	for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
-		if (*p == 0)
-			continue;
-		if ((*p)->tty == tty)
-			(*p)->tty = NULL;
-		if (o_tty && (*p)->tty == o_tty)
-			(*p)->tty = NULL;
-	}
 
 	/*
-	 * Shutdown the current line discipline, and reset it to
-	 * N_TTY.
+	 * Shutdown the current line discipline, and reset it to N_TTY.
+	 * N.B. why reset ldisc when we're releasing the memory??
 	 */
 	if (tty->ldisc.close)
 		(tty->ldisc.close)(tty);
@@ -1155,41 +1288,34 @@
 		o_tty->ldisc = ldiscs[N_TTY];
 	}
 	
-	tty->driver.table[idx] = NULL;
-	if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) {
-		tty->driver.termios[idx] = NULL;
-		kfree_s(tp, sizeof(struct termios));
-	}
-	if (tty == redirect || o_tty == redirect)
-		redirect = NULL;
 	/*
 	 * Make sure that the tty's task queue isn't activated.  If it
-	 * is, take it out of the linked list.
+	 * is, take it out of the linked list.  The tqueue isn't used by
+	 * pty's, so skip the test for them.
 	 */
-	cli();
-	if (tty->flip.tqueue.sync) {
-		struct tq_struct *tq, *prev;
+	if (tty->driver.type != TTY_DRIVER_TYPE_PTY) {
+		cli();
+		if (tty->flip.tqueue.sync) {
+			struct tq_struct *tq, *prev;
 
-		for (tq=tq_timer, prev=0; tq; prev=tq, tq=tq->next) {
-			if (tq == &tty->flip.tqueue) {
-				if (prev)
-					prev->next = tq->next;
-				else
-					tq_timer = tq->next;
-				break;
+			for (tq=tq_timer, prev=0; tq; prev=tq, tq=tq->next) {
+				if (tq == &tty->flip.tqueue) {
+					if (prev)
+						prev->next = tq->next;
+					else
+						tq_timer = tq->next;
+					break;
+				}
 			}
 		}
+		sti();
 	}
-	sti();
-	tty->magic = 0;
-	(*tty->driver.refcount)--;
-	free_page((unsigned long) tty);
-	filp->private_data = 0;
-	if (o_tty) {
-		o_tty->magic = 0;
-		(*o_tty->driver.refcount)--;
-		free_page((unsigned long) o_tty);
-	}
+
+	/* 
+	 * The release_mem function takes care of the details of clearing
+	 * the slots and preserving the termios structure.
+	 */
+	release_mem(tty, idx);
 }
 
 /*
@@ -1274,11 +1400,6 @@
 	return 0;
 }
 
-/*
- * Note that releasing a pty master also releases the child, so
- * we have to make the redirection checks after that and on both
- * sides of a pty.
- */
 static void tty_release(struct inode * inode, struct file * filp)
 {
 	release_dev(filp);
diff -urN linux-2.0.31-pre5/drivers/char/tty_ioctl.c linux-2.0.31-pre6/drivers/char/tty_ioctl.c
--- linux-2.0.31-pre5/drivers/char/tty_ioctl.c	1995-09-17 22:54:08.000000000 -0700
+++ linux-2.0.31-pre6/drivers/char/tty_ioctl.c	2003-08-15 15:04:01.000000000 -0700
@@ -376,7 +376,6 @@
 {
 	struct tty_struct * real_tty;
 	int retval;
-	int opt = 0;
 
 	if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
 	    tty->driver.subtype == PTY_TYPE_MASTER)
@@ -414,19 +413,19 @@
 				    sizeof (struct termios));
 			return 0;
 		case TCSETSF:
-			opt |= TERMIOS_FLUSH;
+			return set_termios(real_tty, arg, TERMIOS_FLUSH);
 		case TCSETSW:
-			opt |= TERMIOS_WAIT;
+			return set_termios(real_tty, arg, TERMIOS_WAIT);
 		case TCSETS:
-			return set_termios(real_tty, arg, opt);
+			return set_termios(real_tty, arg, 0);
 		case TCGETA:
 			return get_termio(real_tty,(struct termio *) arg);
 		case TCSETAF:
-			opt |= TERMIOS_FLUSH;
+			return set_termios(real_tty, arg, TERMIOS_FLUSH | TERMIOS_TERMIO);
 		case TCSETAW:
-			opt |= TERMIOS_WAIT;
+			return set_termios(real_tty, arg, TERMIOS_WAIT | TERMIOS_TERMIO);
 		case TCSETA:
-			return set_termios(real_tty, arg, opt|TERMIOS_TERMIO);
+			return set_termios(real_tty, arg, TERMIOS_TERMIO);
 		case TCXONC:
 			retval = tty_check_change(tty);
 			if (retval)
diff -urN linux-2.0.31-pre5/drivers/isdn/isdn_tty.c linux-2.0.31-pre6/drivers/isdn/isdn_tty.c
--- linux-2.0.31-pre5/drivers/isdn/isdn_tty.c	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/drivers/isdn/isdn_tty.c	2003-08-15 15:04:01.000000000 -0700
@@ -2445,13 +2445,16 @@
  * Get phone-number from modem-commandbuffer
  */
 static void
-isdn_tty_getdial(char *p, char *q)
+isdn_tty_getdial(char *p, char *q, int max)
 {
 	int first = 1;
 
-	while (strchr("0123456789,#.*WPTS-", *p) && *p) {
-		if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first))
+	max--;
+	while (strchr("0123456789,#.*WPTS-", *p) && *p && (max > 0)) {
+		if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first)) {
 			*q++ = *p;
+			max--;
+		}
 		p++;
 		first = 0;
 	}
@@ -3092,7 +3095,7 @@
 				break;
 			case 'D':
 				/* D - Dial */
-				isdn_tty_getdial(++p, ds);
+				isdn_tty_getdial(++p, ds, sizeof(ds));
 				p += strlen(p);
 				if (!strlen(m->msn))
 					isdn_tty_modem_result(10, info);
diff -urN linux-2.0.31-pre5/drivers/net/3c509.c linux-2.0.31-pre6/drivers/net/3c509.c
--- linux-2.0.31-pre5/drivers/net/3c509.c	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/drivers/net/3c509.c	2003-08-15 15:04:01.000000000 -0700
@@ -279,8 +279,10 @@
 	memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
-	dev->if_port = if_port;
-
+	if (dev->mem_start)
+		dev->if_port = dev->mem_start & 3;
+	else
+		dev->if_port = if_port;
 	request_region(dev->base_addr, EL3_IO_EXTENT, "3c509");
 
 	{
@@ -692,8 +694,9 @@
 				printk("%s: Couldn't allocate a sk_buff of size %d.\n",
 					   dev->name, pkt_len);
 		}
-		lp->stats.rx_dropped++;
 		outw(RxDiscard, ioaddr + EL3_CMD);
+		lp->stats.rx_dropped++;
+		SLOW_DOWN_IO;
 		while (inw(ioaddr + EL3_STATUS) & 0x1000)
 			printk("	Waiting for 3c509 to discard packet, status %x.\n",
 				   inw(ioaddr + EL3_STATUS) );
@@ -724,7 +727,7 @@
 		outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast, ioaddr + EL3_CMD);
 	}
 	else
-                outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
+		outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
 }
 
 static int
diff -urN linux-2.0.31-pre5/drivers/net/3c59x.c linux-2.0.31-pre6/drivers/net/3c59x.c
--- linux-2.0.31-pre5/drivers/net/3c59x.c	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/drivers/net/3c59x.c	2003-08-15 15:04:01.000000000 -0700
@@ -40,14 +40,8 @@
    Setting to > 1512 effectively disables this feature. */
 static const rx_copybreak = 200;
 
-#include <linux/config.h>
-#ifdef MODULE
 #include <linux/version.h>
 #include <linux/module.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff -urN linux-2.0.31-pre5/drivers/net/Config.in linux-2.0.31-pre6/drivers/net/Config.in
--- linux-2.0.31-pre5/drivers/net/Config.in	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/drivers/net/Config.in	2003-08-15 15:04:01.000000000 -0700
@@ -50,7 +50,7 @@
       tristate '3c507 support' CONFIG_EL16
     fi
     tristate '3c509/3c579 support' CONFIG_EL3
-    tristate '3c590 series (592/595/597) "Vortex" support' CONFIG_VORTEX
+    tristate '3c590/3c900 series (592/595/597/900/905) "Vortex/Boomerang" support' CONFIG_VORTEX
   fi
   bool 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE
   if [ "$CONFIG_LANCE" = "y" ]; then
@@ -98,6 +98,7 @@
       tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
     fi
     tristate 'Apricot Xen-II on board ethernet' CONFIG_APRICOT
+    tristate 'Intel EtherExpress/Pro 100B support' CONFIG_EEXPRESS_PRO100B
     tristate 'DE425, DE434, DE435, DE450, DE500 support' CONFIG_DE4X5
     tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP
     tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
diff -urN linux-2.0.31-pre5/drivers/net/dgrs.c linux-2.0.31-pre6/drivers/net/dgrs.c
--- linux-2.0.31-pre5/drivers/net/dgrs.c	1996-12-21 07:22:33.000000000 -0800
+++ linux-2.0.31-pre6/drivers/net/dgrs.c	2003-08-15 15:04:01.000000000 -0700
@@ -97,7 +97,6 @@
 #include <linux/skbuff.h>
 
 #include <linux/types.h>
-#include <linux/config.h>	/* for CONFIG_PCI */
 
 /*
  *	API changed at linux version 2.1.0
diff -urN linux-2.0.31-pre5/drivers/net/eepro100.c linux-2.0.31-pre6/drivers/net/eepro100.c
--- linux-2.0.31-pre5/drivers/net/eepro100.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre6/drivers/net/eepro100.c	2003-08-15 15:04:01.000000000 -0700
@@ -0,0 +1,1731 @@
+/* drivers/net/eepro100.c: An Intel i82557 ethernet driver for linux. */
+/*
+   NOTICE: this version tested with kernels 1.3.72 and later only!
+	Written 1996 by Donald Becker.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License, incorporated herein by reference.
+
+	This driver is for the Intel EtherExpress Pro 100B boards.
+	It should work with other i82557 boards (if any others exist).
+	To use a built-in driver, install as drivers/net/eepro100.c.
+	To use as a module, use the compile-command at the end of the file.
+
+	The author may be reached as becker@CESDIS.usra.edu, or C/O
+	Center of Excellence in Space Data and Information Sciences
+	   Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771
+	For updates see
+	<base href="http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html">
+*/
+
+static const char *version =
+"eepro100.c:v0.32 4/8/97 Donald Becker linux-eepro100@cesdis.gsfc.nasa.gov\n";
+
+/* A few user-configurable values that apply to all boards.
+   First set are undocumented and spelled per Intel recommendations. */
+
+static int congenb = 0;		/* Enable congestion control in the DP83840. */
+static int txfifo = 8;		/* Tx FIFO threshold in 4 byte units, 0-15 */
+static int rxfifo = 8;		/* Rx FIFO threshold, default 32 bytes. */
+static int txdmacount = 0;	/* Tx DMA burst length, 0-127, default 0. */
+static int rxdmacount = 0;	/* Rx DMA length, 0 means no preemption. */
+
+/* If defined use the copy-only-tiny-buffer scheme for higher performance.
+   The value sets the copy breakpoint.  Lower uses more memory, but is
+   faster. */
+#define SKBUFF_RX_COPYBREAK 256
+
+#include <linux/config.h>
+#include <linux/version.h>
+#ifdef MODULE
+#include <linux/module.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <asm/processor.h>		/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+/* A nominally proper method to handle version dependencies is to use
+   LINUX_VERSION_CODE in version.h, but that triggers recompiles w/'make'. */
+#define VERSION(v,p,s) (((v)<<16)+(p<<8)+s)
+#ifdef MODULE
+#if (LINUX_VERSION_CODE < VERSION(1,3,0))
+#define KERNEL_1_2
+#else /* 1.3.0 */
+#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
+#define NEW_MULTICAST
+#define LINUX_1_4
+#else
+#warning "This driver is tested for 1.3.44 and later development kernels only."
+#endif /* 1.3.44 */
+#endif
+#else
+
+#if (LINUX_VERSION_CODE >= 0x10344)
+#define NEW_MULTICAST
+#include <linux/delay.h>
+#endif
+
+#ifdef HAVE_HEADER_CACHE
+#define LINUX_1_4
+#define NEW_MULTICAST
+#else
+#ifdef ETH_P_DDCMP				/* Warning: Bogus!  This means IS_LINUX_1_3. */
+#define KERNEL_1_3
+#else
+#define KERNEL_1_2
+#endif
+#endif
+
+#endif
+/* This should be in a header file. */
+#if (LINUX_VERSION_CODE < VERSION(1,3,44))
+struct device *init_etherdev(struct device *dev, int sizeof_priv,
+							 unsigned long *mem_startp);
+#endif
+#if LINUX_VERSION_CODE < 0x10300
+#define RUN_AT(x) (x)			/* What to put in timer->expires.  */
+#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC)
+#define virt_to_bus(addr)  ((unsigned long)addr)
+#define bus_to_virt(addr) ((void*)addr)
+#else  /* 1.3.0 and later */
+#define RUN_AT(x) (jiffies + (x))
+#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
+#endif
+
+/* The total I/O port extent of the board.  Nominally 0x18, but rounded up
+   for PCI allocation. */
+#define SPEEDO3_TOTAL_SIZE 0x20
+
+#ifdef HAVE_DEVLIST
+struct netdev_entry eepro100_drv =
+{"EEPro-100", eepro100_init, SPEEDO3_TOTAL_SIZE, NULL};
+#endif
+
+#ifdef SPEEDO3_DEBUG
+int speedo_debug = SPEEDO3_DEBUG;
+#else
+int speedo_debug = 3;
+#endif
+
+/*
+				Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the Intel i82557 "Speedo3" chip, Intel's
+single-chip fast ethernet controller for PCI, as used on the Intel
+EtherExpress Pro 100 adapter.
+
+II. Board-specific settings
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board.  The system BIOS should be set to assign the
+PCI INTA signal to an otherwise unused system IRQ line.  While it's
+possible to share PCI interrupt lines, it negatively impacts performance and
+only recent kernels support it. 
+
+III. Driver operation
+
+IIIA. General
+The Speedo3 is very similar to other Intel network chips, that is to say
+"apparently designed on a different planet".  This chips retains the complex
+Rx and Tx descriptors and multiple buffers pointers as previous chips, but
+also has simplified Tx and Rx buffer modes.  This driver uses the "flexible"
+Tx mode, but in a simplified lower-overhead manner: it associates only a
+single buffer descriptor with each frame descriptor.
+
+Despite the extra space overhead in each recieve skbuff, the driver must use
+the simplified Rx buffer mode to assure that only a single data buffer is
+associated with each RxFD. The driver implements this by reserving space
+for the Rx descriptor at the head of each Rx skbuff
+
+The Speedo-3 has receive and command unit base addresses that are added to
+almost all descriptor pointers.  The driver sets these to zero, so that all
+pointer fields are absolute addresses.
+
+The System Control Block (SCB) of some previous Intel chips exists on the
+chip in both PCI I/O and memory space.  This driver uses the I/O space
+registers, but might switch to memory mapped mode to better support non-x86
+processors.
+
+IIIB. Transmit structure
+
+The driver must use the complex Tx command+descriptor mode in order to
+have a indirect pointer to the skbuff data section.  Each Tx command block
+(TxCB) is associated with a single, immediately appended Tx buffer descriptor
+(TxBD).  A fixed ring of these TxCB+TxBD pairs are kept as part of the
+speedo_private data structure for each adapter instance.
+
+This ring structure is used for all normal transmit packets, but the
+transmit packet descriptors aren't long enough for most non-Tx commands such
+as CmdConfigure.  This is complicated by the possibility that the chip has
+already loaded the link address in the previous descriptor.  So for these
+commands we convert the next free descriptor on the ring to a NoOp, and point
+that descriptor's link to the complex command.
+
+An additional complexity of these non-transmit commands are that they may be
+added asynchronous to the normal transmit queue, so we disable interrupts
+whenever the Tx descriptor ring is manipulated.
+
+A notable aspect of the these special configure commands is that they do
+work with the normal Tx ring entry scavenge method.  The Tx ring scavenge
+is done at interrupt time using the 'dirty_tx' index, and checking for the
+command-complete bit.  While the setup frames may have the NoOp command on the
+Tx ring marked as complete, but not have completed the setup command, this
+is not a problem.  The tx_ring entry can be still safely reused, as the
+tx_skbuff[] entry is always empty for config_cmd and mc_setup frames.
+
+Commands may have bits set e.g. CmdSuspend in the command word to either
+suspend or stop the transmit/command unit.  This driver always flags the last
+command with CmdSuspend, erases the CmdSuspend in the previous command, and
+then issues a CU_RESUME.
+Note: Watch out for the potential race condition here: imagine
+	erasing the previous suspend
+		the chip processes the previous command
+		the chip processes the final command, and suspends
+	doing the CU_RESUME
+		the chip processes the next-yet-valid post-final-command.
+So blindly sending a CU_RESUME is only safe if we do it immediately after
+after erasing the previous CmdSuspend, without the possibility of an
+intervening delay.  Thus the resume command is always within the
+interrupts-disabled region.  This is a timing dependence, but handling this
+condition in a timing-independent way would considerably complicate the code.
+
+Note: In previous generation Intel chips, restarting the command unit was a
+notoriously slow process.  This is presumably no longer true.
+
+IIIC. Receive structure
+
+Because of the bus-master support on the Speedo3 this driver uses the new
+SKBUFF_RX_COPYBREAK scheme, rather than a fixed intermediate receive buffer.
+This scheme allocates full-sized skbuffs as receive buffers.  The value
+SKBUFF_RX_COPYBREAK is used as the copying breakpoint: it is chosen to
+trade-off the memory wasted by passing the full-sized skbuff to the queue
+layer for all frames vs. the copying cost of copying a frame to a
+correctly-sized skbuff.
+
+For small frames the copying cost is negligible (esp. considering that we
+are pre-loading the cache with immediately useful header information), so we
+allocate a new, minimally-sized skbuff.  For large frames the copying cost
+is non-trivial, and the larger copy might flush the cache of useful data, so
+we pass up the skbuff the packet was received into.
+
+IIID. Synchronization
+The driver runs as two independent, single-threaded flows of control.  One
+is the send-packet routine, which enforces single-threaded use by the
+dev->tbusy flag.  The other thread is the interrupt handler, which is single
+threaded by the hardware and other software.
+
+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
+flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
+the 'sp->tx_full' flag.
+
+The interrupt handler has exclusive control over the Rx ring and records stats
+from the Tx ring.  (The Tx-done interrupt can't be selectively turned off, so
+we can't avoid the interrupt overhead by having the Tx routine reap the Tx
+stats.)	 After reaping the stats, it marks the queue entry as empty by setting
+the 'base' to zero.	 Iff the 'sp->tx_full' flag is set, it clears both the
+tx_full and tbusy flags.
+
+IV. Notes
+
+Thanks to Steve Williams of Intel for arranging the non-disclosure agreement
+that stated that I could disclose the information.  But I still resent
+having to sign an Intel NDA when I'm helping Intel sell their own product!
+
+*/
+
+/* A few values that may be tweaked. */
+/* The ring sizes should be a power of two for efficiency. */
+#define TX_RING_SIZE	16		/* Effectively 2 entries fewer. */
+#define RX_RING_SIZE	16
+/* Size of an pre-allocated Rx buffer: <Ethernet MTU> + slack.*/
+#define PKT_BUF_SZ		1536
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  ((400*HZ)/1000)
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+#define INTR_WORK	16
+
+/* How to wait for the command unit to accept a command.
+   Typically this takes 0 ticks. */
+static inline void wait_for_cmd_done(int cmd_ioaddr)
+{
+  short wait = 100;
+  do   ;
+  while(inb(cmd_ioaddr) && --wait >= 0);
+}
+
+/* Operational parameter that usually are not changed. */
+
+#ifndef PCI_VENDOR_ID_INTEL		/* Now defined in linux/pci.h */
+#define PCI_VENDOR_ID_INTEL		0x8086 /* Hmmmm, how did they pick that? */
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_82557
+#define PCI_DEVICE_ID_INTEL_82557	0x1229
+#endif
+
+/* The rest of these values should never change. */
+
+/* Offsets to the various registers.
+   All accesses need not be longword aligned. */
+enum speedo_offsets {
+	SCBStatus = 0, SCBCmd = 2,	/* Rx/Command Unit command and status. */
+	SCBPointer = 4,				/* General purpose pointer. */
+	SCBPort = 8,				/* Misc. commands and operands.  */
+	SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */
+	SCBCtrlMDI = 16,			/* MDI interface control. */
+	SCBEarlyRx = 20,			/* Early receive byte count. */
+};
+/* Commands that can be put in a command list entry. */
+enum commands {
+	CmdNOp = 0, CmdIASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
+	CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7,
+	CmdSuspend = 0x4000,		/* Suspend after completion. */
+	CmdIntr = 0x2000,			/* Interrupt after completion. */
+	CmdTxFlex = 0x0008,			/* Use "Flexible mode" for CmdTx command. */
+};
+
+/* The SCB accepts the following controls for the Tx and Rx units: */
+#define	 CU_START		0x0010
+#define	 CU_RESUME		0x0020
+#define	 CU_STATSADDR	0x0040
+#define	 CU_SHOWSTATS	0x0050	/* Dump statistics counters. */
+#define	 CU_CMD_BASE	0x0060	/* Base address to add to add CU commands. */
+#define	 CU_DUMPSTATS	0x0070	/* Dump then reset stats counters. */
+
+#define	 RX_START	0x0001
+#define	 RX_RESUME	0x0002
+#define	 RX_ABORT	0x0004
+#define	 RX_ADDR_LOAD	0x0006
+#define	 RX_RESUMENR	0x0007
+#define INT_MASK	0x0100
+#define DRVR_INT	0x0200		/* Driver generated interrupt. */
+
+/* The Speedo3 Rx and Tx frame/buffer descriptors. */
+struct descriptor {			/* A generic descriptor. */
+	s16 status;		/* Offset 0. */
+	s16 command;		/* Offset 2. */
+	u32 link;					/* struct descriptor *  */
+	unsigned char params[0];
+};
+
+/* The Speedo3 Rx and Tx buffer descriptors. */
+struct RxFD {					/* Receive frame descriptor. */
+	s32 status;
+	u32 link;					/* struct RxFD * */
+	u32 rx_buf_addr;			/* void * */
+	u16 count;
+	u16 size;
+};
+
+/* Elements of the RxFD.status word. */
+#define RX_COMPLETE 0x8000
+
+struct TxFD {					/* Transmit frame descriptor set. */
+	s32 status;
+	u32 link;					/* void * */
+	u32 tx_desc_addr;			/* Always points to the tx_buf_addr element. */
+	s32 count;					/* # of TBD (=1), Tx start thresh., etc. */
+	/* This constitutes a single "TBD" entry -- we only use one. */
+	u32 tx_buf_addr;			/* void *, frame to be transmitted.  */
+	s32 tx_buf_size;			/* Length of Tx frame. */
+};
+
+/* Elements of the dump_statistics block. This block must be lword aligned. */
+struct speedo_stats {
+	u32 tx_good_frames;
+	u32 tx_coll16_errs;
+	u32 tx_late_colls;
+	u32 tx_underruns;
+	u32 tx_lost_carrier;
+	u32 tx_deferred;
+	u32 tx_one_colls;
+	u32 tx_multi_colls;
+	u32 tx_total_colls;
+	u32 rx_good_frames;
+	u32 rx_crc_errs;
+	u32 rx_align_errs;
+	u32 rx_resource_errs;
+	u32 rx_overrun_errs;
+	u32 rx_colls_errs;
+	u32 rx_runt_errs;
+	u32 done_marker;
+};
+
+struct speedo_private {
+	char devname[8];			/* Used only for kernel debugging. */
+	const char *product_name;
+	struct device *next_module;
+	struct TxFD	tx_ring[TX_RING_SIZE];	/* Commands (usually CmdTxPacket). */
+	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
+	struct sk_buff* tx_skbuff[TX_RING_SIZE];
+	struct descriptor  *last_cmd;	/* Last command sent. */
+	/* Rx descriptor ring & addresses of receive-in-place skbuffs. */
+	struct RxFD *rx_ringp[RX_RING_SIZE];
+	struct sk_buff* rx_skbuff[RX_RING_SIZE];
+#if (LINUX_VERSION_CODE < 0x10300)	/* Kernel v1.2.*. */
+	struct RxFD saved_skhead[RX_RING_SIZE];	/* Saved skbuff header chunk. */
+#endif
+	struct RxFD *last_rxf;	/* Last command sent. */
+	struct enet_statistics stats;
+	struct speedo_stats lstats;
+	struct timer_list timer;	/* Media selection timer. */
+	long last_rx_time;			/* Last Rx, in jiffies, to handle Rx hang. */
+	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
+	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
+	struct descriptor config_cmd;	/* A configure command, with header... */
+	u8 config_cmd_data[22];			/* .. and setup parameters. */
+	int mc_setup_frm_len;			 	/* The length of an allocated.. */
+	struct descriptor *mc_setup_frm; 	/* ..multicast setup frame. */
+	char rx_mode;						/* Current PROMISC/ALLMULTI setting. */
+	unsigned int tx_full:1;				/* The Tx queue is full. */
+	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
+	unsigned int default_port:1;		/* Last dev->if_port value. */
+	unsigned int rx_bug:1;				/* Work around receiver hang errata. */
+	unsigned int rx_bug10:1;			/* Receiver might hang at 10mbps. */
+	unsigned int rx_bug100:1;			/* Receiver might hang at 100mbps. */
+	unsigned short phy[2];				/* PHY media interfaces available. */
+};
+
+/* The parameters for a CmdConfigure operation.
+   There are so many options that it would be difficult to document each bit.
+   We mostly use the default or recommended settings. */
+const char basic_config_cmd[22] = {
+	22, 0x08, 0, 0,  0, 0x80, 0x32, 0x03,  1, /* 1=Use MII  0=Use AUI */
+	0, 0x2E, 0,  0x60, 0,
+	0xf2, 0x48,   0, 0x40, 0xf2, 0x80, 		/* 0x40=Force full-duplex */
+	0x3f, 0x05, };
+
+/* PHY media interface chips. */
+static const char *phys[] = {
+	"None", "i82553-A/B", "i82553-C", "i82503",
+	"DP83840", "80c240", "80c24", "unknown-7",
+	"unknown-8", "unknown-9", "DP83840A", "unknown-11",
+	"unknown-12", "unknown-13", "unknown-14", "unknown-15", };
+enum phy_chips { NonSuchPhy=0, I82553AB, I82553C, I82503, DP83840, S80C240,
+					 S80C24, PhyUndefined, DP83840A=10, };
+static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 };
+
+static void speedo_found1(struct device *dev, int ioaddr, int irq, int options);
+
+static int read_eeprom(int ioaddr, int location);
+static int mdio_read(int ioaddr, int phy_id, int location);
+static int mdio_write(int ioaddr, int phy_id, int location, int value);
+static int speedo_open(struct device *dev);
+static void speedo_timer(unsigned long data);
+static void speedo_init_rx_ring(struct device *dev);
+static int speedo_start_xmit(struct sk_buff *skb, struct device *dev);
+static int speedo_rx(struct device *dev);
+#ifdef SA_SHIRQ
+static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+#else
+static void speedo_interrupt(int irq, struct pt_regs *regs);
+#endif
+static int speedo_close(struct device *dev);
+static struct enet_statistics *speedo_get_stats(struct device *dev);
+static void set_rx_mode(struct device *dev);
+
+
+
+#ifdef MODULE
+/* The parameters that may be passed in... */
+/* 'options' is used to pass a transceiver override or full-duplex flag
+   e.g. "options=16" for FD, "options=32" for 100mbps-only. */
+static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int debug = -1;			/* The debug level */
+
+/* A list of all installed Speedo devices, for removing the driver module. */
+static struct device *root_speedo_dev = NULL;
+#endif
+
+int eepro100_init(struct device *dev)
+{
+	int cards_found = 0;
+
+	if (pcibios_present()) {
+		int pci_index;
+		for (pci_index = 0; pci_index < 8; pci_index++) {
+			unsigned char pci_bus, pci_device_fn, pci_irq_line, pci_latency;
+#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
+			int pci_ioaddr;
+#else
+			long pci_ioaddr;
+#endif
+			unsigned short pci_command;
+
+			if (pcibios_find_device(PCI_VENDOR_ID_INTEL,
+									PCI_DEVICE_ID_INTEL_82557,
+									pci_index, &pci_bus,
+									&pci_device_fn))
+			  break;
+			pcibios_read_config_byte(pci_bus, pci_device_fn,
+									 PCI_INTERRUPT_LINE, &pci_irq_line);
+			/* Note: BASE_ADDRESS_0 is for memory-mapping the registers. */
+			pcibios_read_config_dword(pci_bus, pci_device_fn,
+									  PCI_BASE_ADDRESS_1, &pci_ioaddr);
+			/* Remove I/O space marker in bit 0. */
+			pci_ioaddr &= ~3;
+			if (speedo_debug > 2)
+				printk("Found Intel i82557 PCI Speedo at I/O %#x, IRQ %d.\n",
+					   (int)pci_ioaddr, pci_irq_line);
+
+			/* Get and check the bus-master and latency values. */
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_COMMAND, &pci_command);
+			if ( ! (pci_command & PCI_COMMAND_MASTER)) {
+				printk("  PCI Master Bit has not been set! Setting...\n");
+				pci_command |= PCI_COMMAND_MASTER;
+				pcibios_write_config_word(pci_bus, pci_device_fn,
+										  PCI_COMMAND, pci_command);
+			}
+			pcibios_read_config_byte(pci_bus, pci_device_fn,
+										 PCI_LATENCY_TIMER, &pci_latency);
+			if (pci_latency < 10) {
+				printk("  PCI latency timer (CFLT) is unreasonably low at %d."
+					   "  Setting to 255 clocks.\n", pci_latency);
+				pcibios_write_config_byte(pci_bus, pci_device_fn,
+										  PCI_LATENCY_TIMER, 255);
+			} else if (speedo_debug > 1)
+				printk("  PCI latency timer (CFLT) is %#x.\n", pci_latency);
+
+#ifdef MODULE
+			speedo_found1(dev, pci_ioaddr, pci_irq_line, options[cards_found]);
+#else
+			speedo_found1(dev, pci_ioaddr, pci_irq_line,
+						  dev ? dev->mem_start : 0);
+#endif
+			cards_found++;
+		}
+	}
+
+	return cards_found;
+}
+
+static void speedo_found1(struct device *dev, int ioaddr, int irq, int options)
+{
+	static int did_version = 0;			/* Already printed version info. */
+	struct speedo_private *sp;
+	int i;
+	u16 eeprom[0x40];
+
+	if (speedo_debug > 0  &&  did_version++ == 0)
+		printk(version);
+
+#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
+	dev = init_etherdev(dev, sizeof(struct speedo_private));
+#else
+	dev = init_etherdev(dev, sizeof(struct speedo_private), 0);
+#endif
+
+	/* Read the station address EEPROM before doing the reset.
+	   Perhaps this should even be done before accepting the device,
+	   then we wouldn't have a device name with which to report the error. */
+	{
+		u16 sum = 0;
+		int j;
+		for (j = 0, i = 0; i < 0x40; i++) {
+			unsigned short value = read_eeprom(ioaddr, i);
+			eeprom[i] = value;
+			sum += value;
+			if (i < 3) {
+				dev->dev_addr[j++] = value;
+				dev->dev_addr[j++] = value >> 8;
+			}
+		}
+		if (sum != 0xBABA)
+			printk(KERN_WARNING "%s: Invalid EEPROM checksum %#4.4x, "
+				   "check settings before activating this device!\n",
+				   dev->name, sum);
+		/* Don't  unregister_netdev(dev);  as the EEPro may actually be
+		   usable, especially if the MAC address is set later. */
+	}
+
+	/* Reset the chip: stop Tx and Rx processes and clear counters.
+	   This takes less than 10usec and will easily finish before the next
+	   action. */
+	outl(0, ioaddr + SCBPort);
+
+	printk(KERN_INFO "%s: Intel EtherExpress Pro 10/100 at %#3x, ",
+		   dev->name, ioaddr);
+	for (i = 0; i < 5; i++)
+		printk("%2.2X:", dev->dev_addr[i]);
+	printk("%2.2X, IRQ %d.\n", dev->dev_addr[i], irq);
+
+#ifndef kernel_bloat
+	/* OK, this is pure kernel bloat.  I don't like it when other drivers
+	   waste non-pageable kernel space to emit similar messages, but I need
+	   them for bug reports. */
+	{
+		const char *connectors[] = {" RJ45", " BNC", " AUI", " MII"};
+		/* The self-test results must be paragraph aligned. */
+		int str[6], *volatile self_test_results;
+		int boguscnt = 16000;	/* Timeout for set-test. */
+		if (eeprom[3] & 0x03)
+			printk(KERN_INFO "  Receiver lock-up bug exists -- enabling"
+				   " work-around.\n");
+		printk(KERN_INFO "  Board assembly %4.4x%2.2x-%3.3d, Physical"
+			   " connectors present:",
+			   eeprom[8], eeprom[9]>>8, eeprom[9] & 0xff);
+		for (i = 0; i < 4; i++)
+			if (eeprom[5] & (1<<i))
+				printk(connectors[i]);
+		printk("\n"KERN_INFO"  Primary interface chip %s PHY #%d.\n",
+			   phys[(eeprom[6]>>8)&15], eeprom[6] & 0x1f);
+		if (eeprom[7] & 0x0700)
+			printk(KERN_INFO "    Secondary interface chip %s.\n",
+				   phys[(eeprom[7]>>8)&7]);
+#if defined(notdef)
+		/* ToDo: Read and set PHY registers through MDIO port. */
+		for (i = 0; i < 2; i++)
+			printk("  MDIO register %d is %4.4x.\n",
+				   i, mdio_read(ioaddr, eeprom[6] & 0x1f, i));
+		for (i = 5; i < 7; i++)
+			printk("  MDIO register %d is %4.4x.\n",
+				   i, mdio_read(ioaddr, eeprom[6] & 0x1f, i));
+		printk("  MDIO register %d is %4.4x.\n",
+			   25, mdio_read(ioaddr, eeprom[6] & 0x1f, 25));
+#endif
+		if (((eeprom[6]>>8) & 0x3f) == DP83840
+			||  ((eeprom[6]>>8) & 0x3f) == DP83840A) {
+			int mdi_reg23 = mdio_read(ioaddr, eeprom[6] & 0x1f, 23) | 0x0422;
+			if (congenb)
+			  mdi_reg23 |= 0x0100;
+			printk("  DP83840 specific setup, setting register 23 to %4.4x.\n",
+				   mdi_reg23);
+			mdio_write(ioaddr, eeprom[6] & 0x1f, 23, mdi_reg23);
+		}
+		if ((options >= 0) && (options & 0x60)) {
+			printk(KERN_INFO "  Forcing %dMbs %s-duplex operation.\n",
+				   (options & 0x20 ? 100 : 10),
+				   (options & 0x10 ? "full" : "half"));
+			mdio_write(ioaddr, eeprom[6] & 0x1f, 0,
+					   ((options & 0x20) ? 0x2000 : 0) | 	/* 100mbps? */
+					   ((options & 0x10) ? 0x0100 : 0)); /* Full duplex? */
+		}
+
+		/* Perform a system self-test. */
+		self_test_results = (int*) ((((int) str) + 15) & ~0xf);
+		self_test_results[0] = 0;
+		self_test_results[1] = -1;
+		outl(virt_to_bus(self_test_results) | 1, ioaddr + SCBPort);
+		do {
+#ifdef _LINUX_DELAY_H
+			udelay(10);
+#else
+			SLOW_DOWN_IO;
+#endif
+		} while (self_test_results[1] == -1  &&  --boguscnt >= 0);
+
+		if (boguscnt < 0) {		/* Test optimized out. */
+			printk(KERN_ERR "Self test failed, status %8.8x:\n"
+				   KERN_ERR " Failure to initialize the i82557.\n"
+				   KERN_ERR " Verify that the card is a bus-master"
+				   " capable slot.\n",
+				   self_test_results[1]);
+		} else 
+			printk(KERN_INFO "  General self-test: %s.\n"
+				   KERN_INFO "  Serial sub-system self-test: %s.\n"
+				   KERN_INFO "  Internal registers self-test: %s.\n"
+				   KERN_INFO "  ROM checksum self-test: %s (%#8.8x).\n",
+				   self_test_results[1] & 0x1000 ? "failed" : "passed",
+				   self_test_results[1] & 0x0020 ? "failed" : "passed",
+				   self_test_results[1] & 0x0008 ? "failed" : "passed",
+				   self_test_results[1] & 0x0004 ? "failed" : "passed",
+				   self_test_results[0]);
+	}
+#endif  /* kernel_bloat */
+
+	/* We do a request_region() only to register /proc/ioports info. */
+	request_region(ioaddr, SPEEDO3_TOTAL_SIZE, "Intel Speedo3 Ethernet");
+
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+
+	if (dev->priv == NULL)
+		dev->priv = kmalloc(sizeof(*sp), GFP_KERNEL);
+	sp = dev->priv;
+	memset(sp, 0, sizeof(*sp));
+#ifdef MODULE
+	sp->next_module = root_speedo_dev;
+	root_speedo_dev = dev;
+#endif
+
+	sp->full_duplex = options >= 0 && (options & 0x10) ? 1 : 0;
+	sp->default_port = options >= 0 ? (options & 0x0f) : 0;
+
+	sp->phy[0] = eeprom[6];
+	sp->phy[1] = eeprom[7];
+	sp->rx_bug = (eeprom[3] & 0x03) == 3 ? 0 : 1;
+
+	printk(KERN_INFO "  Operating in %s duplex mode.\n",
+		   sp->full_duplex ? "full" : "half");
+	if (sp->rx_bug)
+	  printk(KERN_INFO "  Reciever lock-up workaround activated.\n");
+
+	/* The Speedo-specific entries in the device structure. */
+	dev->open = &speedo_open;
+	dev->hard_start_xmit = &speedo_start_xmit;
+	dev->stop = &speedo_close;
+	dev->get_stats = &speedo_get_stats;
+#ifdef NEW_MULTICAST
+	dev->set_multicast_list = &set_rx_mode;
+#endif
+
+	return;
+}
+
+/* Serial EEPROM section.
+   A "bit" grungy, but we work our way through bit-by-bit :->. */
+/*  EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK	0x01	/* EEPROM shift clock. */
+#define EE_CS			0x02	/* EEPROM chip select. */
+#define EE_DATA_WRITE	0x04	/* EEPROM chip data in. */
+#define EE_WRITE_0		0x01
+#define EE_WRITE_1		0x05
+#define EE_DATA_READ	0x08	/* EEPROM chip data out. */
+#define EE_ENB			(0x4800 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+   This is a "nasty" timing loop, but PC compatible machines are defined
+   to delay an ISA compatible period for the SLOW_DOWN_IO macro.  */
+#define eeprom_delay(nanosec)	do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD	(5 << 6)
+#define EE_READ_CMD		(6 << 6)
+#define EE_ERASE_CMD	(7 << 6)
+
+static int read_eeprom(int ioaddr, int location)
+{
+	int i;
+	unsigned short retval = 0;
+	int ee_addr = ioaddr + SCBeeprom;
+	int read_cmd = location | EE_READ_CMD;
+	
+	outw(EE_ENB & ~EE_CS, ee_addr);
+	outw(EE_ENB, ee_addr);
+	
+	/* Shift the read command bits out. */
+	for (i = 10; i >= 0; i--) {
+		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+		outw(EE_ENB | dataval, ee_addr);
+		eeprom_delay(100);
+		outw(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay(150);
+		outw(EE_ENB | dataval, ee_addr);	/* Finish EEPROM a clock tick. */
+		eeprom_delay(250);
+	}
+	outw(EE_ENB, ee_addr);
+	
+	for (i = 15; i >= 0; i--) {
+		outw(EE_ENB | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay(100);
+		retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0);
+		outw(EE_ENB, ee_addr);
+		eeprom_delay(100);
+	}
+
+	/* Terminate the EEPROM access. */
+	outw(EE_ENB & ~EE_CS, ee_addr);
+	return retval;
+}
+
+static int mdio_read(int ioaddr, int phy_id, int location)
+{
+	int val, boguscnt = 64*4;		/* <64 usec. to complete, typ 27 ticks */
+	outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI);
+	do {
+#ifdef _LINUX_DELAY_H
+		udelay(16);
+#else
+		SLOW_DOWN_IO;
+#endif
+		val = inl(ioaddr + SCBCtrlMDI);
+		if (--boguscnt < 0) {
+			printk(KERN_ERR " mdio_read() timed out with val = %8.8x.\n", val);
+		}
+	} while (! (val & 0x10000000));
+	return val & 0xffff;
+}
+
+static int mdio_write(int ioaddr, int phy_id, int location, int value)
+{
+	int val, boguscnt = 64*4;		/* <64 usec. to complete, typ 27 ticks */
+	outl(0x04000000 | (location<<16) | (phy_id<<21) | value,
+		 ioaddr + SCBCtrlMDI);
+	do {
+#ifdef _LINUX_DELAY_H
+		udelay(16);
+#else
+		SLOW_DOWN_IO;
+#endif
+		val = inl(ioaddr + SCBCtrlMDI);
+		if (--boguscnt < 0) {
+			printk(KERN_ERR" mdio_write() timed out with val = %8.8x.\n", val);
+		}
+	} while (! (val & 0x10000000));
+	return val & 0xffff;
+}
+
+
+static int
+speedo_open(struct device *dev)
+{
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+
+#ifdef notdef
+	/* We could reset the chip, but should not need to. */
+	outl(0, ioaddr + SCBPort);
+	for (i = 40; i >= 0; i--)
+		SLOW_DOWN_IO;			/* At least 250ns */
+#endif
+
+#ifdef SA_SHIRQ
+	if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ,
+					"Intel EtherExpress Pro 10/100 Ethernet", dev)) {
+		return -EAGAIN;
+	}
+#else
+#ifdef USE_SHARED_IRQ
+	if (request_shared_irq(dev->irq, &speedo_interrupt, dev,
+						   "Intel EtherExpress Pro 10/100 Ethernet"))
+		return -EAGAIN;
+#else
+	if (dev->irq < 2  ||  dev->irq > 15  ||  irq2dev_map[dev->irq] != NULL)
+		return -EAGAIN;
+	irq2dev_map[dev->irq] = dev;
+	if (request_irq(dev->irq, &speedo_interrupt, 0, "Intel EtherExpress Pro 10/100 Ethernet")) {
+		irq2dev_map[dev->irq] = NULL;
+		return -EAGAIN;
+	}
+#endif
+#endif
+
+	if (speedo_debug > 1)
+		printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
+
+	MOD_INC_USE_COUNT;
+
+	/* Load the statistics block address. */
+	outl(virt_to_bus(&sp->lstats), ioaddr + SCBPointer);
+	outw(INT_MASK | CU_STATSADDR, ioaddr + SCBCmd);
+	sp->lstats.done_marker = 0;
+
+	speedo_init_rx_ring(dev);
+	outl(0, ioaddr + SCBPointer);
+	outw(INT_MASK | RX_ADDR_LOAD, ioaddr + SCBCmd);
+
+	/* Todo: verify that we must wait for previous command completion. */
+	wait_for_cmd_done(ioaddr + SCBCmd);
+	outl(virt_to_bus(sp->rx_ringp[0]), ioaddr + SCBPointer);
+	outw(INT_MASK | RX_START, ioaddr + SCBCmd);
+
+	/* Fill the first command with our physical address. */
+	{ 
+		unsigned short *eaddrs = (unsigned short *)dev->dev_addr;
+		unsigned short *setup_frm = (short *)&(sp->tx_ring[0].tx_desc_addr);
+
+		/* Avoid a bug(?!) here by marking the command already completed. */
+		sp->tx_ring[0].status = ((CmdSuspend | CmdIASetup) << 16) | 0xa000;
+		sp->tx_ring[0].link = virt_to_bus(&(sp->tx_ring[1]));
+		*setup_frm++ = eaddrs[0];
+		*setup_frm++ = eaddrs[1];
+		*setup_frm++ = eaddrs[2];
+	}
+	sp->last_cmd = (struct descriptor *)&sp->tx_ring[0];
+	sp->cur_tx = 1;
+	sp->dirty_tx = 0;
+	sp->tx_full = 0;
+
+	outl(0, ioaddr + SCBPointer);
+	outw(INT_MASK | CU_CMD_BASE, ioaddr + SCBCmd);
+
+	dev->if_port = sp->default_port;
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	/* Start the chip's Tx process and unmask interrupts. */
+	/* Todo: verify that we must wait for previous command completion. */
+	wait_for_cmd_done(ioaddr + SCBCmd);
+	outl(virt_to_bus(&sp->tx_ring[0]), ioaddr + SCBPointer);
+	outw(CU_START, ioaddr + SCBCmd);
+
+	/* Setup the chip and configure the multicast list. */
+	sp->mc_setup_frm = NULL;
+	sp->mc_setup_frm_len = 0;
+	sp->rx_mode = -1;			/* Invalid -> always reset the mode. */
+	set_rx_mode(dev);
+
+	if (speedo_debug > 2) {
+		printk(KERN_DEBUG "%s: Done speedo_open(), status %8.8x.\n",
+			   dev->name, inw(ioaddr + SCBStatus));
+	}
+	/* Set the timer.  The timer serves a dual purpose:
+	   1) to monitor the media interface (e.g. link beat) and perhaps switch
+	   to an alternate media type
+	   2) to monitor Rx activity, and restart the Rx process if the receiver
+	   hangs. */
+	init_timer(&sp->timer);
+	sp->timer.expires = RUN_AT((24*HZ)/10); 			/* 2.4 sec. */
+	sp->timer.data = (unsigned long)dev;
+	sp->timer.function = &speedo_timer;					/* timer handler */
+	add_timer(&sp->timer);
+
+	outw(CU_DUMPSTATS, ioaddr + SCBCmd);
+	return 0;
+}
+
+/* Media monitoring and control. */
+static void speedo_timer(unsigned long data)
+{
+	struct device *dev = (struct device *)data;
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	int tickssofar = jiffies - sp->last_rx_time;
+
+	if (speedo_debug > 3) {
+		int ioaddr = dev->base_addr;
+		printk(KERN_DEBUG "%s: Media selection tick, status %4.4x.\n",
+			   dev->name, inw(ioaddr + SCBStatus));
+	}
+	if (sp->rx_bug) {
+		if (tickssofar > 2*HZ  || sp->rx_mode < 0) {
+			/* We haven't received a packet in a Long Time.  We might have been
+			   bitten by the receiver hang bug.  This can be cleared by sending
+			   a set multicast list command. */
+			set_rx_mode(dev);
+		}
+		/* We must continue to monitor the media. */
+		sp->timer.expires = RUN_AT(2*HZ); 			/* 2.0 sec. */
+		add_timer(&sp->timer);
+	}
+}
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void
+speedo_init_rx_ring(struct device *dev)
+{
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct RxFD *rxf, *last_rxf = NULL;
+	int i;
+
+	sp->cur_rx = 0;
+	sp->dirty_rx = RX_RING_SIZE - 1;
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb;
+#ifndef KERNEL_1_2
+		skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
+#else
+		skb = alloc_skb(PKT_BUF_SZ, GFP_ATOMIC);
+#endif
+		sp->rx_skbuff[i] = skb;
+		if (skb == NULL)
+			break;			/* Bad news!  */
+		skb->dev = dev;			/* Mark as being used by this device. */
+
+#if LINUX_VERSION_CODE >= 0x10300
+		rxf = (struct RxFD *)skb->tail;
+		skb_reserve(skb, sizeof(struct RxFD));
+#else
+		/* Save the data in the header region -- it's restored later. */
+		rxf = (struct RxFD *)(skb->data - sizeof(struct RxFD));
+		memcpy(&sp->saved_skhead[i], rxf, sizeof(struct RxFD));
+#endif
+		sp->rx_ringp[i] = rxf;
+		if (last_rxf)
+			last_rxf->link = virt_to_bus(rxf);
+		last_rxf = rxf;
+		rxf->status = 0x00000001; 			/* '1' is flag value only. */
+		rxf->link = 0;						/* None yet. */
+#if LINUX_VERSION_CODE < 0x10300
+		/* This field unused by i82557, we use it as a consistency check. */
+		rxf->rx_buf_addr = virt_to_bus(skb->data);
+#else
+		rxf->rx_buf_addr = virt_to_bus(skb->tail);
+#endif
+		rxf->count = 0;
+		rxf->size = PKT_BUF_SZ;
+	}
+	/* Mark the last entry as end-of-list. */
+	last_rxf->status = 0xC0000002; 			/* '2' is flag value only. */
+	sp->last_rxf = last_rxf;
+}
+
+static void speedo_tx_timeout(struct device *dev)
+{
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int i;
+
+	printk(KERN_WARNING "%s: Transmit timed out: status %4.4x "
+		   "command %4.4x.\n",
+		   dev->name, inw(ioaddr + SCBStatus), inw(ioaddr + SCBCmd));
+#ifndef final_version
+	printk("%s:  Tx timeout  fill index %d  scavenge index %d.\n",
+		   dev->name, sp->cur_tx, sp->dirty_tx);
+	printk("    Tx queue ");
+	for (i = 0; i < TX_RING_SIZE; i++)
+	  printk(" %8.8x", (int)sp->tx_ring[i].status);
+	printk(".\n    Rx ring ");
+	for (i = 0; i < RX_RING_SIZE; i++)
+	  printk(" %8.8x", (int)sp->rx_ringp[i]->status);
+	printk(".\n");
+		
+#else
+	dev->if_port ^= 1;
+	printk("  (Media type switching not yet implemented.)\n");
+	/* Do not do 'dev->tbusy = 0;' there -- it is incorrect. */
+#endif
+	if ((inw(ioaddr + SCBStatus) & 0x00C0) != 0x0080) {
+	  printk("%s: Trying to restart the transmitter...\n", dev->name);
+	  outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]),
+		   ioaddr + SCBPointer);
+	  outw(CU_START, ioaddr + SCBCmd);
+	} else {
+	  outw(DRVR_INT, ioaddr + SCBCmd);
+	}
+	sp->stats.tx_errors++;
+	dev->trans_start = jiffies;
+	return;
+}
+
+static int
+speedo_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int entry;
+
+	if (skb == NULL || skb->len <= 0) {
+		printk(KERN_ERR "%s: Obsolete driver layer request made: skbuff==NULL.\n",
+			   dev->name);
+		dev_tint(dev);
+		return 0;
+	}
+
+	/* Block a timer-based transmit from overlapping.  This could better be
+	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
+	   If this ever occurs the queue layer is doing something evil! */
+	if (set_bit(0, (void*)&dev->tbusy) != 0) {
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < TX_TIMEOUT - 2)
+			return 1;
+		if (tickssofar < TX_TIMEOUT) {
+			/* Reap sent packets from the full Tx queue. */
+			outw(DRVR_INT, ioaddr + SCBCmd);
+			return 1;
+		}
+		speedo_tx_timeout(dev);
+		return 0;
+	}
+
+	/* Caution: the write order is important here, set the base address
+	   with the "ownership" bits last. */
+
+	{	/* Prevent interrupts from changing the Tx ring from underneath us. */
+		unsigned long flags;
+
+		save_flags(flags);
+		cli();
+		/* Calculate the Tx descriptor entry. */
+		entry = sp->cur_tx++ % TX_RING_SIZE;
+
+		sp->tx_skbuff[entry] = skb;
+		/* Todo: be a little more clever about setting the interrupt bit. */
+		sp->tx_ring[entry].status =
+			(CmdSuspend | CmdTx | CmdTxFlex) << 16;
+		sp->tx_ring[entry].link =
+		  virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]);
+		sp->tx_ring[entry].tx_desc_addr =
+		  virt_to_bus(&sp->tx_ring[entry].tx_buf_addr);
+		/* The data region is always in one buffer descriptor, Tx FIFO
+		   threshold of 256. */
+		sp->tx_ring[entry].count = 0x01208000;
+		sp->tx_ring[entry].tx_buf_addr = virt_to_bus(skb->data);
+		sp->tx_ring[entry].tx_buf_size = skb->len;
+		/* Todo: perhaps leave the interrupt bit set if the Tx queue is more
+		   than half full.  Argument against: we should be receiving packets
+		   and scavenging the queue.  Argument for: if so, it shouldn't
+		   matter. */
+		sp->last_cmd->command &= ~(CmdSuspend | CmdIntr);
+		sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
+		/* Trigger the command unit resume. */
+		outw(CU_RESUME, ioaddr + SCBCmd);
+		restore_flags(flags);
+	}
+
+	/* Leave room for set_rx_mode() to fill two entries. */
+	if (sp->cur_tx - sp->dirty_tx > TX_RING_SIZE - 3)
+		sp->tx_full = 1;
+	else
+		dev->tbusy = 0;
+
+	dev->trans_start = jiffies;
+
+	return 0;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+   after the Tx thread. */
+#ifdef SA_SHIRQ
+static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+#else
+static void speedo_interrupt(int irq, struct pt_regs *regs)
+#endif
+{
+#ifdef SA_SHIRQ
+	struct device *dev = (struct device *)dev_instance;
+#else
+#ifdef USE_SHARED_IRQ
+	struct device *dev = (struct device *)(irq == 0 ? regs : irq2dev_map[irq]);
+#else
+	struct device *dev = (struct device *)(irq2dev_map[irq]);
+#endif
+#endif
+	struct speedo_private *sp;
+	int ioaddr, boguscnt = INTR_WORK;
+	unsigned short status;
+
+#ifndef final_version
+	if (dev == NULL) {
+		printk(KERN_ERR "speedo_interrupt(): irq %d for unknown device.\n", irq);
+		return;
+	}
+#endif
+
+	ioaddr = dev->base_addr;
+	sp = (struct speedo_private *)dev->priv;
+#ifndef final_version
+	if (dev->interrupt) {
+		printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
+		return;
+	}
+	dev->interrupt = 1;
+#endif
+
+	do {
+		status = inw(ioaddr + SCBStatus);
+		/* Acknowledge all of the current interrupt sources ASAP. */
+		outw(status & 0xfc00, ioaddr + SCBStatus);
+
+		if (speedo_debug > 4)
+			printk(KERN_DEBUG "%s: interrupt  status=%#4.4x.\n",
+				   dev->name, status);
+
+		if ((status & 0xfc00) == 0)
+			break;
+
+		if (status & 0x4000)	 /* Packet received. */
+			speedo_rx(dev);
+
+		if (status & 0x1000) {
+#ifdef notdef
+		  int i;
+		  printk(KERN_WARNING"%s: The EEPro100 receiver left the ready"
+				 " state -- %4.4x!  Index %d (%d).\n", dev->name, status,
+				 sp->cur_rx, sp->cur_rx % RX_RING_SIZE);
+		  printk("   Rx ring:\n ");
+		  for (i = 0; i < RX_RING_SIZE; i++)
+			printk("   %d %8.8x %8.8x %8.8x %d %d.\n",
+				   i, sp->rx_ringp[i]->status, sp->rx_ringp[i]->link,
+				   sp->rx_ringp[i]->rx_buf_addr, sp->rx_ringp[i]->count,
+				   sp->rx_ringp[i]->size);
+#endif
+
+		  if ((status & 0x003c) == 0x0028) /* No more Rx buffers. */
+			outw(RX_RESUMENR, ioaddr + SCBCmd);
+		  else if ((status & 0x003c) == 0x0008) { /* No resources (why?!) */
+			/* No idea of what went wrong.  Restart the receiver. */
+			outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]),
+				 ioaddr + SCBPointer);
+			outw(RX_START, ioaddr + SCBCmd);
+		  }
+		  sp->stats.rx_errors++;
+		}
+
+		/* User interrupt, Command/Tx unit interrupt or CU not active. */
+		if (status & 0xA400) {
+			unsigned int dirty_tx = sp->dirty_tx;
+
+			while (sp->cur_tx - dirty_tx > 0) {
+				int entry = dirty_tx % TX_RING_SIZE;
+				int status = sp->tx_ring[entry].status;
+
+				if (speedo_debug > 5)
+					printk(KERN_DEBUG " scavenge canidate %d status %4.4x.\n",
+						   entry, status);
+				if ((status & 0x8000) == 0)
+					break;			/* It still hasn't been processed. */
+				/* Free the original skb. */
+				if (sp->tx_skbuff[entry]) {
+					sp->stats.tx_packets++;	/* Count only user packets. */
+					dev_kfree_skb(sp->tx_skbuff[entry], FREE_WRITE);
+					sp->tx_skbuff[entry] = 0;
+				}
+				dirty_tx++;
+			}
+
+#ifndef final_version
+			if (sp->cur_tx - dirty_tx > TX_RING_SIZE) {
+				printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+					   dirty_tx, sp->cur_tx, sp->tx_full);
+				dirty_tx += TX_RING_SIZE;
+			}
+#endif
+
+			if (sp->tx_full && dev->tbusy
+				&& dirty_tx > sp->cur_tx - TX_RING_SIZE + 2) {
+				/* The ring is no longer full, clear tbusy. */
+				sp->tx_full = 0;
+				dev->tbusy = 0;
+				mark_bh(NET_BH);
+			}
+
+			sp->dirty_tx = dirty_tx;
+		}
+
+		if (--boguscnt < 0) {
+			printk("%s: Too much work at interrupt, status=0x%4.4x.\n",
+				   dev->name, status);
+			/* Clear all interrupt sources. */
+			outl(0xfc00, ioaddr + SCBStatus);
+			break;
+		}
+	} while (1);
+
+	if (speedo_debug > 3)
+		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
+			   dev->name, inw(ioaddr + SCBStatus));
+
+#ifndef final_version
+	/* Special code for testing *only*. */
+	{
+		static int stopit = 100;
+		if (dev->start == 0  &&  --stopit < 0) {
+			printk(KERN_ALERT "%s: Emergency stop, interrupt is stuck.\n",
+				   dev->name);
+#ifdef SA_SHIRQ
+			free_irq(irq, dev);
+#else
+			free_irq(irq);
+#endif
+		}
+	}
+#endif
+
+	dev->interrupt = 0;
+	return;
+}
+
+static int
+speedo_rx(struct device *dev)
+{
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	int entry = sp->cur_rx % RX_RING_SIZE;
+	int status;
+		
+	if (speedo_debug > 4)
+		printk(KERN_DEBUG " In speedo_rx().\n");
+	/* If we own the next entry, it's a new packet. Send it up. */
+	while ((status = sp->rx_ringp[entry]->status) & RX_COMPLETE) {
+
+		if (speedo_debug > 4)
+			printk(KERN_DEBUG "  speedo_rx() status %8.8x len %d.\n", status,
+				   sp->rx_ringp[entry]->count & 0x3fff);
+		if (status & 0x0200) {
+			printk("%s: Ethernet frame overran the Rx buffer, status %8.8x!\n",
+				   dev->name, status);
+		} else if ( ! (status & 0x2000)) {
+			/* There was a fatal error.  This *should* be impossible. */
+			sp->stats.rx_errors++;
+			printk("%s: Anomalous event in speedo_rx(), status %8.8x.\n",
+				   dev->name, status);
+		} else {
+			/* Malloc up new buffer, compatible with net-2e. */
+			short pkt_len = sp->rx_ringp[entry]->count & 0x3fff;
+			struct sk_buff *skb;
+			int rx_in_place = 0;
+
+			/* Check if the packet is long enough to just accept without
+			   copying to a properly sized skbuff. */
+			if (pkt_len > SKBUFF_RX_COPYBREAK) {
+				struct sk_buff *newskb;
+				char *temp;
+
+				/* Pass up the skb already on the Rx ring. */
+				skb = sp->rx_skbuff[entry];
+#ifdef KERNEL_1_2
+				temp = skb->data;
+				if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
+					printk("%s: Warning -- the skbuff addresses do not match"
+						   " in speedo_rx: %p vs. %p / %p.\n", dev->name,
+						   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
+						   temp, skb->data);
+				/* Get a fresh skbuff to replace the filled one. */
+				newskb = alloc_skb(PKT_BUF_SZ, GFP_ATOMIC);
+#else
+				temp = skb_put(skb, pkt_len);
+				if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)
+					printk("%s: Warning -- the skbuff addresses do not match"
+						   " in speedo_rx: %8.8x vs. %p / %p.\n", dev->name,
+						   sp->rx_ringp[entry]->rx_buf_addr, skb->head, temp);
+				/* Get a fresh skbuff to replace the filled one. */
+				newskb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));
+#endif
+				if (newskb) {
+					struct RxFD *rxf;
+					rx_in_place = 1;
+					sp->rx_skbuff[entry] = newskb;
+					newskb->dev = dev;
+#ifdef KERNEL_1_2
+					/* Restore the data in the old header region. */
+					memcpy(skb->data - sizeof(struct RxFD),
+						   &sp->saved_skhead[entry], sizeof(struct RxFD));
+					/* Save the data in this header region. */
+					rxf = (struct RxFD *)(newskb->data - sizeof(struct RxFD));
+					sp->rx_ringp[entry] = rxf;
+					memcpy(&sp->saved_skhead[entry], rxf, sizeof(struct RxFD));
+					rxf->rx_buf_addr = virt_to_bus(newskb->data);
+#else
+					rxf = sp->rx_ringp[entry] = (struct RxFD *)newskb->tail;
+					skb_reserve(newskb, sizeof(struct RxFD));
+					/* Unused by i82557, consistency check only. */
+					rxf->rx_buf_addr = virt_to_bus(newskb->tail);
+#endif
+					rxf->status = 0x00000001;
+				} else			/* No memory, drop the packet. */
+				  skb = 0;
+			} else
+#ifdef KERNEL_1_2
+				skb = alloc_skb(pkt_len, GFP_ATOMIC);
+#else
+				skb = dev_alloc_skb(pkt_len + 2);
+#endif
+			if (skb == NULL) {
+				int i;
+				printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+				/* Check that at least two ring entries are free.
+				   If not, free one and mark stats->rx_dropped++. */
+				/* ToDo: This is not correct!!!!  We should count the number
+				   of linked-in Rx buffer to very that we have at least two
+				   remaining. */
+				for (i = 0; i < RX_RING_SIZE; i++)
+					if (! ((sp->rx_ringp[(entry+i) % RX_RING_SIZE]->status)
+						   & RX_COMPLETE))
+						break;
+
+				if (i > RX_RING_SIZE -2) {
+					sp->stats.rx_dropped++;
+					sp->rx_ringp[entry]->status = 0;
+					sp->cur_rx++;
+				}
+				break;
+			}
+			skb->dev = dev;
+#if (LINUX_VERSION_CODE >= VERSION(1,3,44))
+			if (! rx_in_place) {
+				skb_reserve(skb, 2);	/* 16 byte align the data fields */
+				memcpy(skb_put(skb, pkt_len),
+					   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len);
+			}
+			skb->protocol = eth_type_trans(skb, dev);
+#else
+#ifdef KERNEL_1_3
+#warning This code has only been tested with later 1.3.* kernels.
+			skb->len = pkt_len;
+			memcpy(skb->data, bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),
+				   pkt_len);
+			/* Needed for 1.3.*. */
+			skb->protocol = eth_type_trans(skb, dev);
+#else	/* KERNEL_1_2 */
+			skb->len = pkt_len;
+			if (! rx_in_place) {
+				memcpy(skb->data,
+					   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len);
+			}
+#endif
+#endif
+			netif_rx(skb);
+			sp->stats.rx_packets++;
+		}
+
+		/*	ToDo: This is better than before, but should be checked. */
+		{ 
+			struct RxFD *rxf = sp->rx_ringp[entry];
+			rxf->status = 0xC0000003; 		/* '3' for verification only */
+			rxf->link = 0;			/* None yet. */
+			rxf->count = 0;
+			rxf->size = PKT_BUF_SZ;
+			sp->last_rxf->link = virt_to_bus(rxf);
+			sp->last_rxf->status &= ~0xC0000000;
+			sp->last_rxf = rxf;
+			entry = (++sp->cur_rx) % RX_RING_SIZE;
+		}
+	}
+
+	sp->last_rx_time = jiffies;
+	return 0;
+}
+
+static int
+speedo_close(struct device *dev)
+{
+	int ioaddr = dev->base_addr;
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	int i;
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	if (speedo_debug > 1)
+		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n",
+			   dev->name, inw(ioaddr + SCBStatus));
+
+	/* Shut off the media monitoring timer. */
+	del_timer(&sp->timer);
+
+	/* Disable interrupts, and stop the chip's Rx process. */
+	outw(INT_MASK, ioaddr + SCBCmd);
+	outw(INT_MASK | RX_ABORT, ioaddr + SCBCmd);
+
+#ifdef SA_SHIRQ
+	free_irq(dev->irq, dev);
+#else
+	free_irq(dev->irq);
+	irq2dev_map[dev->irq] = 0;
+#endif
+
+	/* Free all the skbuffs in the Rx and Tx queues. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb = sp->rx_skbuff[i];
+		sp->rx_skbuff[i] = 0;
+		/* Clear the Rx descriptors. */
+		if (skb)
+			dev_kfree_skb(skb, FREE_WRITE);
+	}
+
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		struct sk_buff *skb = sp->tx_skbuff[i];
+		sp->tx_skbuff[i] = 0;
+		/* Clear the Tx descriptors. */
+		if (skb)
+			dev_kfree_skb(skb, FREE_WRITE);
+	}
+	if (sp->mc_setup_frm) {
+		kfree(sp->mc_setup_frm);
+		sp->mc_setup_frm_len = 0;
+	}
+
+	/* Print a few items for debugging. */
+	if (speedo_debug > 3) {
+		printk("%s:Printing Rx ring (next to receive into %d).\n",
+			   dev->name, sp->cur_rx);
+
+		for (i = 0; i < RX_RING_SIZE; i++)
+			printk("  Rx ring entry %d  %8.8x.\n",
+				   i, (int)sp->rx_ringp[i]->status);
+
+		for (i = 0; i < 5; i++)
+			printk("  PHY index %d register %d is %4.4x.\n",
+				   1, i, mdio_read(ioaddr, 1, i));
+		for (i = 21; i < 26; i++)
+			printk("  PHY index %d register %d is %4.4x.\n",
+				   1, i, mdio_read(ioaddr, 1, i));
+	}
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+/* The Speedo-3 has an especially awkward and unusable method of getting
+   statistics out of the chip.  It takes an unpredictable length of time
+   for the dump-stats command to complete.  To avoid a busy-wait loop we
+   update the stats with the previous dump results, and then trigger a
+   new dump.
+
+   These problems are mitigated by the current /proc implementation, which
+   calls this routine first to judge the output length, and then to emit the
+   output.
+
+   Oh, and incoming frames are dropped while executing dump-stats!
+   */
+static struct enet_statistics *
+speedo_get_stats(struct device *dev)
+{
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+
+	if (sp->lstats.done_marker == 0xA007) {	/* Previous dump finished */
+		sp->stats.tx_aborted_errors += sp->lstats.tx_coll16_errs;
+		sp->stats.tx_window_errors += sp->lstats.tx_late_colls;
+		sp->stats.tx_fifo_errors += sp->lstats.tx_underruns;
+		sp->stats.tx_fifo_errors += sp->lstats.tx_lost_carrier;
+		/*sp->stats.tx_deferred += sp->lstats.tx_deferred;*/
+		sp->stats.collisions += sp->lstats.tx_total_colls;
+		sp->stats.rx_crc_errors += sp->lstats.rx_crc_errs;
+		sp->stats.rx_frame_errors += sp->lstats.rx_align_errs;
+		sp->stats.rx_over_errors += sp->lstats.rx_resource_errs;
+		sp->stats.rx_fifo_errors += sp->lstats.rx_overrun_errs;
+		sp->stats.rx_length_errors += sp->lstats.rx_runt_errs;
+		sp->lstats.done_marker = 0x0000;
+		if (dev->start)
+			outw(CU_DUMPSTATS, ioaddr + SCBCmd);
+	}
+	return &sp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+   This is very ugly with Intel chips -- we usually have to execute an
+   entire configuration command, plus process a multicast command.
+   This is complicated.  We must put a large configuration command and
+   an arbitrarily-sized multicast command in the transmit list.
+   To minimize the disruption -- the previous command might have already
+   loaded the link -- we convert the current command block, normally a Tx
+   command, into a no-op and link it to the new command.
+*/
+static void
+set_rx_mode(struct device *dev)
+{
+	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	char new_rx_mode;
+	unsigned long flags;
+	int entry, i;
+
+	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
+		new_rx_mode = 3;
+	} else if (dev->flags & IFF_ALLMULTI) {
+		new_rx_mode = 1;
+	} else
+		new_rx_mode = 0;
+
+	if (sp->cur_tx - sp->dirty_tx >= TX_RING_SIZE - 1) {
+	  /* The Tx ring is full -- don't add anything!  Presumably the new mode
+	     is in config_cmd_data and will be added anyway. */
+		sp->rx_mode = -1;
+		return;
+	}
+
+	if (new_rx_mode != sp->rx_mode) {
+		/* We must change the configuration. Construct a CmdConfig frame. */
+		memcpy(sp->config_cmd_data, basic_config_cmd,sizeof(basic_config_cmd));
+		sp->config_cmd_data[1] = (txfifo << 4) | rxfifo;
+		sp->config_cmd_data[4] = rxdmacount;
+		sp->config_cmd_data[5] = txdmacount + 0x80;
+		sp->config_cmd_data[15] = (new_rx_mode & 2) ? 0x49 : 0x48;
+		sp->config_cmd_data[19] = sp->full_duplex ? 0xC0 : 0x80;
+		sp->config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05;
+		if (sp->phy[0] & 0x8000) {			/* Use the AUI port instead. */
+		  sp->config_cmd_data[15] |= 0x80;
+		  sp->config_cmd_data[8] = 0;
+		}
+		save_flags(flags);
+		cli();
+		/* Fill the "real" tx_ring frame with a no-op and point it to us. */
+		entry = sp->cur_tx++ % TX_RING_SIZE;
+		sp->tx_skbuff[entry] = 0;	/* Nothing to free. */
+		sp->tx_ring[entry].status = CmdNOp << 16;
+		sp->tx_ring[entry].link = virt_to_bus(&sp->config_cmd);
+		sp->config_cmd.status = 0;
+		sp->config_cmd.command = CmdSuspend | CmdConfigure;
+		sp->config_cmd.link =
+		  virt_to_bus(&(sp->tx_ring[sp->cur_tx % TX_RING_SIZE]));
+		sp->last_cmd->command &= ~CmdSuspend;
+		/* Immediately trigger the command unit resume. */
+		outw(CU_RESUME, ioaddr + SCBCmd);
+		sp->last_cmd = &sp->config_cmd;
+		restore_flags(flags);
+		if (speedo_debug > 5) {
+			int i;
+			printk(" CmdConfig frame in entry %d.\n", entry);
+			for(i = 0; i < 32; i++)
+				printk(" %2.2x", ((unsigned char *)&sp->config_cmd)[i]);
+			printk(".\n");
+		}
+	}
+
+	if (new_rx_mode == 0  &&  dev->mc_count < 3) {
+		/* The simple case of 0-2 multicast list entries occurs often, and
+		   fits within one tx_ring[] entry. */
+		u16 *setup_params;
+		unsigned short *eaddrs;
+		struct dev_mc_list *mclist;
+
+		save_flags(flags);
+		cli();
+		entry = sp->cur_tx++ % TX_RING_SIZE;
+		sp->tx_skbuff[entry] = 0;
+		sp->tx_ring[entry].status = (CmdSuspend | CmdMulticastList) << 16;
+		sp->tx_ring[entry].link =
+		  virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]);
+		sp->tx_ring[entry].tx_desc_addr = 0; /* Really MC list count. */
+		setup_params = (short *)&sp->tx_ring[entry].tx_desc_addr;
+		*setup_params++ = dev->mc_count*6;
+		/* Fill in the multicast addresses. */
+		for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
+			 i++, mclist = mclist->next) {
+			eaddrs = (unsigned short *)mclist->dmi_addr;
+			*setup_params++ = *eaddrs++;
+			*setup_params++ = *eaddrs++;
+			*setup_params++ = *eaddrs++;
+		}
+
+		sp->last_cmd->command &= ~CmdSuspend;
+		/* Immediately trigger the command unit resume. */
+		outw(CU_RESUME, ioaddr + SCBCmd);
+		sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];
+		restore_flags(flags);
+	} else if (new_rx_mode == 0) {
+		/* This does not work correctly, but why not? */
+		struct dev_mc_list *mclist;
+		unsigned short *eaddrs;
+		struct descriptor *mc_setup_frm = sp->mc_setup_frm;
+		u16 *setup_params = (short *)mc_setup_frm->params;
+		int i;
+
+		if (sp->mc_setup_frm_len < 10 + dev->mc_count*6
+			|| sp->mc_setup_frm == NULL) {
+			/* Allocate a new frame, 10bytes + addrs, with a few
+			   extra entries for growth. */
+			if (sp->mc_setup_frm)
+				kfree(sp->mc_setup_frm);
+			sp->mc_setup_frm_len = 10 + dev->mc_count*6 + 24;
+			printk("%s: Allocating a setup frame of size %d.\n",
+				   dev->name, sp->mc_setup_frm_len);
+			sp->mc_setup_frm = kmalloc(sp->mc_setup_frm_len,
+									   intr_count ? GFP_ATOMIC : GFP_KERNEL);
+			if (sp->mc_setup_frm == NULL) {
+			  printk("%s: Failed to allocate a setup frame.\n", dev->name);
+				sp->rx_mode = -1; /* We failed, try again. */
+				return;
+			}
+		}
+		mc_setup_frm = sp->mc_setup_frm;
+		/* Construct the new setup frame. */
+		printk("%s: Constructing a setup frame at %p, %d bytes.\n",
+			   dev->name, sp->mc_setup_frm, sp->mc_setup_frm_len);
+		mc_setup_frm->status = 0;
+		mc_setup_frm->command = CmdSuspend | CmdIntr | CmdMulticastList;
+		/* Link set below. */
+		setup_params = (short *)mc_setup_frm->params;
+		*setup_params++ = dev->mc_count*6;
+		/* Fill in the multicast addresses. */
+		for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
+			 i++, mclist = mclist->next) {
+			eaddrs = (unsigned short *)mclist->dmi_addr;
+			*setup_params++ = *eaddrs++;
+			*setup_params++ = *eaddrs++;
+			*setup_params++ = *eaddrs++;
+		}
+		
+		/* Disable interrupts while playing with the Tx Cmd list. */
+		save_flags(flags);
+		cli();
+		entry = sp->cur_tx++ % TX_RING_SIZE;
+
+		if (speedo_debug > 5)
+			printk(" CmdMCSetup frame length %d in entry %d.\n",
+				   dev->mc_count, entry);
+
+		/* Change the command to a NoOp, pointing to the CmdMulti command. */
+		sp->tx_skbuff[entry] = 0;
+		sp->tx_ring[entry].status = CmdNOp << 16;
+		sp->tx_ring[entry].link = virt_to_bus(mc_setup_frm);
+
+		/* Set the link in the setup frame. */
+		mc_setup_frm->link =
+		  virt_to_bus(&(sp->tx_ring[sp->cur_tx % TX_RING_SIZE]));
+
+		sp->last_cmd->command &= ~CmdSuspend;
+		/* Immediately trigger the command unit resume. */
+		outw(CU_RESUME, ioaddr + SCBCmd);
+		sp->last_cmd = mc_setup_frm;
+		restore_flags(flags);
+		printk("%s: Last command at %p is %4.4x.\n",
+			   dev->name, sp->last_cmd, sp->last_cmd->command);
+	}
+
+	sp->rx_mode = new_rx_mode;
+}
+
+#ifdef MODULE
+#if (LINUX_VERSION_CODE < VERSION(1,3,38))	/* 1.3.38 and later */
+char kernel_version[] = UTS_RELEASE;
+#endif
+
+int
+init_module(void)
+{
+	int cards_found;
+
+	if (debug >= 0)
+		speedo_debug = debug;
+	if (speedo_debug)
+		printk(KERN_INFO "%s", version);
+
+	root_speedo_dev = NULL;
+	cards_found = eepro100_init(NULL);
+	return cards_found < 0 ? cards_found : 0;
+}
+
+void
+cleanup_module(void)
+{
+	struct device *next_dev;
+
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (root_speedo_dev) {
+		next_dev = ((struct speedo_private *)root_speedo_dev->priv)->next_module;
+		unregister_netdev(root_speedo_dev);
+		release_region(root_speedo_dev->base_addr, SPEEDO3_TOTAL_SIZE);
+		kfree(root_speedo_dev);
+		root_speedo_dev = next_dev;
+	}
+}
+#else   /* not MODULE */
+int eepro100_probe(struct device *dev)
+{
+	int cards_found = 0;
+
+	cards_found = eepro100_init(dev);
+
+	if (speedo_debug > 0  &&  cards_found)
+		printk(version);
+
+	return cards_found ? 0 : -ENODEV;
+}
+#endif  /* MODULE */
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DCONFIG_MODVERSIONS -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c"
+ *  c-indent-level: 4
+ *  tab-width: 4
+ * End:
+ */
diff -urN linux-2.0.31-pre5/drivers/net/Makefile linux-2.0.31-pre6/drivers/net/Makefile
--- linux-2.0.31-pre5/drivers/net/Makefile	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/drivers/net/Makefile	2003-08-15 15:04:01.000000000 -0700
@@ -320,6 +320,15 @@
   endif
 endif
 
+ifeq ($(CONFIG_EEXPRESS_PRO100B),y)
+L_OBJS += eepro100.o
+else
+  ifeq ($(CONFIG_EEXPRESS_PRO100B),m)
+  M_OBJS += eepro100.o
+  endif
+endif
+
+
 ifeq ($(CONFIG_WAVELAN),y)
 L_OBJS += wavelan.o
 else
diff -urN linux-2.0.31-pre5/drivers/net/ne.c linux-2.0.31-pre6/drivers/net/ne.c
--- linux-2.0.31-pre5/drivers/net/ne.c	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/drivers/net/ne.c	2003-08-15 15:04:01.000000000 -0700
@@ -62,9 +62,11 @@
 /* Do we have a non std. amount of memory? (in units of 256 byte pages) */
 /* #define PACKETBUF_MEMSIZE	0x40 */
 
+#if defined(HAVE_DEVLIST) || !defined(MODULE)
 /* A zero-terminated list of I/O addresses to be probed. */
 static unsigned int netcard_portlist[] =
 { 0x300, 0x280, 0x320, 0x340, 0x360, 0};
+#endif /* defined(HAVE_DEVLIST) || !defined(MODULE) */
 
 #ifdef CONFIG_PCI
 /* Ack! People are making PCI ne2000 clones! Oh the horror, the horror... */
@@ -160,7 +162,9 @@
 
 int ne_probe(struct device *dev)
 {
+#ifndef MODULE
     int i;
+#endif /* MODULE */
     int base_addr = dev ? dev->base_addr : 0;
 
     /* First check any supplied i/o locations. User knows best. <cough> */
diff -urN linux-2.0.31-pre5/drivers/net/smc-ultra32.c linux-2.0.31-pre6/drivers/net/smc-ultra32.c
--- linux-2.0.31-pre5/drivers/net/smc-ultra32.c	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/drivers/net/smc-ultra32.c	2003-08-15 15:04:01.000000000 -0700
@@ -47,7 +47,6 @@
 
 
 #include <linux/module.h>
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
diff -urN linux-2.0.31-pre5/drivers/net/Space.c linux-2.0.31-pre6/drivers/net/Space.c
--- linux-2.0.31-pre5/drivers/net/Space.c	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/drivers/net/Space.c	2003-08-15 15:04:01.000000000 -0700
@@ -50,6 +50,7 @@
 extern int znet_probe(struct device *);
 extern int express_probe(struct device *);
 extern int eepro_probe(struct device *);
+extern int eepro100_probe(struct device *);
 extern int el3_probe(struct device *);
 extern int at1500_probe(struct device *);
 extern int at1700_probe(struct device *);
@@ -163,6 +164,9 @@
 #ifdef CONFIG_EEXPRESS_PRO	/* Intel EtherExpress Pro/10 */
 	&& eepro_probe(dev)
 #endif
+#ifdef CONFIG_EEXPRESS_PRO100B	/* Intel EtherExpress Pro100B */
+	&& eepro100_probe(dev)
+#endif
 #ifdef CONFIG_DEPCA		/* DEC DEPCA */
 	&& depca_probe(dev)
 #endif
diff -urN linux-2.0.31-pre5/drivers/scsi/aic7xxx/aic7xxx.reg linux-2.0.31-pre6/drivers/scsi/aic7xxx/aic7xxx.reg
--- linux-2.0.31-pre5/drivers/scsi/aic7xxx/aic7xxx.reg	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/drivers/scsi/aic7xxx/aic7xxx.reg	2003-08-15 15:04:01.000000000 -0700
@@ -1079,6 +1079,21 @@
 	CUR_SCBID {
 		size		1
 	}
+	/*
+	 * Running count of commands placed in
+	 * the QOUTFIFO.  This is cleared by the
+	 * kernel driver every FIFODEPTH commands.
+	 */
+	CMDOUTCNT {
+		size		1
+	}
+	/*
+	 * Maximum number of entries allowed in
+	 * the QOUT/INFIFO.
+	 */
+	FIFODEPTH {
+		size		1
+	}
 	ARG_1 {
 		size		1
 		mask	SEND_MSG	0x80
diff -urN linux-2.0.31-pre5/drivers/scsi/aic7xxx/aic7xxx.seq linux-2.0.31-pre6/drivers/scsi/aic7xxx/aic7xxx.seq
--- linux-2.0.31-pre5/drivers/scsi/aic7xxx/aic7xxx.seq	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/drivers/scsi/aic7xxx/aic7xxx.seq	2003-08-15 15:04:01.000000000 -0700
@@ -643,6 +643,15 @@
 
 complete:
 	/* Post the SCB and issue an interrupt */
+.if ( SCB_PAGING )
+	/*
+	 * Spin loop until there is space
+	 * in the QOUTFIFO.
+	 */
+	mov	A, FIFODEPTH;
+	cmp	CMDOUTCNT, A	je .;
+	inc	CMDOUTCNT;
+.endif
 	mov	QOUTFIFO,SCB_TAG;
 	mvi	INTSTAT,CMDCMPLT;
 	test	SCB_CONTROL, ABORT_SCB jz dma_next_scb;
diff -urN linux-2.0.31-pre5/drivers/scsi/aic7xxx.c linux-2.0.31-pre6/drivers/scsi/aic7xxx.c
--- linux-2.0.31-pre5/drivers/scsi/aic7xxx.c	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/drivers/scsi/aic7xxx.c	2003-08-15 15:04:01.000000000 -0700
@@ -829,6 +829,7 @@
   unsigned char            pause;            /* pause value for HCNTRL */
   unsigned char            qcntmask;
   unsigned char            qfullcount;
+  unsigned char            cmdoutcnt;
   unsigned char            curqincnt;
   struct Scsi_Host        *next;             /* allow for multiple IRQs */
   unsigned char            activescbs;       /* active scbs */
@@ -3880,6 +3881,19 @@
 #endif
     while (qoutcnt > 0)
     {
+      if ((p->flags & PAGE_ENABLED) != 0)
+      {
+        p->cmdoutcnt += qoutcnt;
+        if (p->cmdoutcnt >= p->qfullcount)
+        {
+          /*
+           * Since paging only occurs on aic78x0 chips, we can use
+           * Auto Access Pause to clear the command count.
+           */
+          outb(0, p->base + CMDOUTCNT);
+          p->cmdoutcnt = 0;
+        }
+      }
       for (i = 0; i < qoutcnt; i++)
       {
         scb_index = inb(p->base + QOUTFIFO);
@@ -4638,9 +4652,9 @@
     {
       old_verbose = aic7xxx_verbose;
       printk(KERN_INFO "aic7xxx: Warning - detected auto-termination.  Please "
-                       "verify driver");
+                       "verify driver\n");
       printk(KERN_INFO "         detected settings and use manual termination "
-                       "if necessary."); 
+                       "if necessary.\n"); 
 
       /* Configure auto termination. */
       outb(SEECS | SEEMS, p->base + SEECTL);
@@ -5291,6 +5305,9 @@
     */
   outb(p->qcntmask, p->base + QCNTMASK);
 
+  outb(p->qfullcount, p->base + FIFODEPTH);
+  outb(0, p->base + CMDOUTCNT);
+
   /*
    * We don't have any waiting selections or disconnected SCBs.
    */
diff -urN linux-2.0.31-pre5/drivers/scsi/aic7xxx_reg.h linux-2.0.31-pre6/drivers/scsi/aic7xxx_reg.h
--- linux-2.0.31-pre5/drivers/scsi/aic7xxx_reg.h	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/drivers/scsi/aic7xxx_reg.h	2003-08-15 15:04:01.000000000 -0700
@@ -252,15 +252,19 @@
 
 #define	CUR_SCBID       		0x58
 
-#define	ARG_1           		0x59
-#define	RETURN_1        		0x59
-#define		SEND_MSG        	0x80
-#define		SEND_SENSE      	0x40
-#define		SEND_REJ        	0x20
+#define	CMDOUTCNT       		0x59
 
 #define	SCSICONF        		0x5a
 #define		RESET_SCSI      	0x40
 
+#define	FIFODEPTH       		0x5a
+
+#define	ARG_1           		0x5b
+#define	RETURN_1        		0x5b
+#define		SEND_MSG        	0x80
+#define		SEND_SENSE      	0x40
+#define		SEND_REJ        	0x20
+
 #define	HOSTCONF        		0x5d
 
 #define	HA_274_BIOSCTRL 		0x5f
diff -urN linux-2.0.31-pre5/drivers/scsi/aic7xxx_seq.h linux-2.0.31-pre6/drivers/scsi/aic7xxx_seq.h
--- linux-2.0.31-pre5/drivers/scsi/aic7xxx_seq.h	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/drivers/scsi/aic7xxx_seq.h	2003-08-15 15:04:01.000000000 -0700
@@ -16,28 +16,28 @@
 	0xff, 0x48, 0x2c, 0x18,
 	0xff, 0x40, 0x64, 0x02,
 	0x00, 0x9c, 0x03, 0x1e,
-	0x00, 0x6a, 0xaa, 0x17,
+	0x00, 0x6a, 0xad, 0x17,
 	0xff, 0x65, 0x03, 0x1c,
 	0xff, 0x9b, 0x58, 0x02,
 	0xff, 0x58, 0x90, 0x02,
 	0x0d, 0x6a, 0x3d, 0x00,
-	0x00, 0x58, 0x74, 0x17,
+	0x00, 0x58, 0x77, 0x17,
 	0x28, 0xa0, 0x2a, 0x1a,
 	0x50, 0x6a, 0x60, 0x00,
 	0xff, 0x90, 0x4a, 0x02,
-	0x00, 0xa1, 0x9e, 0x17,
-	0xff, 0x6c, 0x59, 0x02,
-	0xff, 0x59, 0x27, 0x1c,
+	0x00, 0xa1, 0xa1, 0x17,
+	0xff, 0x6c, 0x5b, 0x02,
+	0xff, 0x5b, 0x27, 0x1c,
 	0xff, 0x4a, 0x90, 0x02,
-	0x00, 0x65, 0xa7, 0x17,
-	0x00, 0x6a, 0x4f, 0x17,
+	0x00, 0x65, 0xaa, 0x17,
+	0x00, 0x6a, 0x52, 0x17,
 	0xff, 0x65, 0x1f, 0x18,
 	0x51, 0x6a, 0x91, 0x00,
 	0xff, 0x58, 0xb3, 0x02,
-	0x00, 0x65, 0xb8, 0x17,
+	0x00, 0x65, 0xbb, 0x17,
 	0x10, 0x6a, 0x60, 0x00,
 	0x00, 0x65, 0x03, 0x10,
-	0xff, 0x59, 0x90, 0x02,
+	0xff, 0x5b, 0x90, 0x02,
 	0xff, 0x58, 0xb3, 0x02,
 	0x10, 0x6a, 0x60, 0x00,
 	0x00, 0x65, 0x03, 0x10,
@@ -121,26 +121,26 @@
 	0x7d, 0x6a, 0x3d, 0x00,
 	0x00, 0x65, 0x7a, 0x10,
 	0x08, 0x6a, 0x66, 0x00,
-	0xa9, 0x6a, 0x71, 0x17,
+	0xa9, 0x6a, 0x74, 0x17,
 	0x00, 0x65, 0x82, 0x10,
 	0x79, 0x6a, 0x3d, 0x00,
-	0x00, 0x65, 0x4c, 0x17,
+	0x00, 0x65, 0x4f, 0x17,
 	0x10, 0x41, 0x76, 0x1a,
 	0x88, 0x6a, 0x66, 0x00,
-	0xac, 0x6a, 0x6d, 0x17,
-	0x00, 0x65, 0x6a, 0x17,
+	0xac, 0x6a, 0x70, 0x17,
+	0x00, 0x65, 0x6d, 0x17,
 	0xff, 0xa3, 0x43, 0x02,
 	0x44, 0x6a, 0x66, 0x00,
-	0xa4, 0x6a, 0x70, 0x17,
+	0xa4, 0x6a, 0x73, 0x17,
 	0xff, 0x43, 0x88, 0x1a,
 	0x80, 0x02, 0x02, 0x00,
 	0xff, 0x6a, 0x8c, 0x00,
 	0xff, 0x6a, 0x8d, 0x00,
 	0xff, 0x6a, 0x8e, 0x00,
-	0x00, 0x65, 0x6a, 0x17,
+	0x00, 0x65, 0x6d, 0x17,
 	0x01, 0x43, 0x8a, 0x18,
 	0xbf, 0x3d, 0x3d, 0x02,
-	0x00, 0x3d, 0x41, 0x17,
+	0x00, 0x3d, 0x44, 0x17,
 	0x80, 0x02, 0xa2, 0x1a,
 	0xff, 0x65, 0x9c, 0x1e,
 	0xff, 0x43, 0x43, 0x06,
@@ -149,14 +149,14 @@
 	0x08, 0x44, 0x44, 0x06,
 	0x00, 0x45, 0x45, 0x08,
 	0x88, 0x6a, 0x66, 0x00,
-	0x44, 0x6a, 0x70, 0x17,
+	0x44, 0x6a, 0x73, 0x17,
 	0x08, 0x6a, 0x8c, 0x00,
 	0xff, 0x6a, 0x8d, 0x02,
 	0xff, 0x6a, 0x8e, 0x02,
 	0x0d, 0x93, 0x93, 0x00,
-	0x00, 0x65, 0x9a, 0x17,
-	0x88, 0x6a, 0x92, 0x17,
-	0x00, 0x65, 0x6a, 0x17,
+	0x00, 0x65, 0x9d, 0x17,
+	0x88, 0x6a, 0x95, 0x17,
+	0x00, 0x65, 0x6d, 0x17,
 	0x10, 0x0c, 0x82, 0x1e,
 	0xff, 0x08, 0xa9, 0x02,
 	0xff, 0x09, 0xaa, 0x02,
@@ -167,19 +167,19 @@
 	0x7f, 0x02, 0x02, 0x02,
 	0xe1, 0x6a, 0x91, 0x00,
 	0x00, 0x65, 0x5c, 0x10,
-	0x00, 0x65, 0x4c, 0x17,
+	0x00, 0x65, 0x4f, 0x17,
 	0x88, 0x6a, 0x66, 0x00,
-	0xb4, 0x6a, 0x6f, 0x17,
+	0xb4, 0x6a, 0x72, 0x17,
 	0xff, 0x6a, 0x8d, 0x02,
 	0xff, 0x6a, 0x8e, 0x02,
-	0x00, 0x65, 0x6a, 0x17,
-	0x3d, 0x6a, 0x41, 0x17,
+	0x00, 0x65, 0x6d, 0x17,
+	0x3d, 0x6a, 0x44, 0x17,
 	0x00, 0x65, 0x5c, 0x10,
-	0x00, 0x65, 0x4c, 0x17,
+	0x00, 0x65, 0x4f, 0x17,
 	0xff, 0x06, 0xa2, 0x02,
 	0x00, 0x65, 0x5c, 0x10,
 	0xff, 0x34, 0xb2, 0x1a,
-	0x08, 0x6a, 0x2f, 0x17,
+	0x08, 0x6a, 0x32, 0x17,
 	0x35, 0x6a, 0x65, 0x00,
 	0xff, 0x34, 0x66, 0x02,
 	0x01, 0x0c, 0xb4, 0x1e,
@@ -197,116 +197,119 @@
 	0x40, 0x6a, 0x0c, 0x00,
 	0xff, 0x6a, 0x34, 0x02,
 	0x00, 0x65, 0x5c, 0x10,
-	0x64, 0x6a, 0x3c, 0x17,
+	0x64, 0x6a, 0x3f, 0x17,
 	0xff, 0x64, 0x4b, 0x02,
-	0x80, 0x64, 0x0b, 0x1b,
-	0x04, 0x64, 0xfe, 0x1c,
-	0x02, 0x64, 0x01, 0x1d,
+	0x80, 0x64, 0x0e, 0x1b,
+	0x04, 0x64, 0x01, 0x1d,
+	0x02, 0x64, 0x04, 0x1d,
 	0x00, 0x6a, 0xd1, 0x1c,
-	0x03, 0x64, 0x09, 0x1d,
-	0x01, 0x64, 0xf2, 0x1c,
-	0x07, 0x64, 0x2d, 0x1d,
+	0x03, 0x64, 0x0c, 0x1d,
+	0x01, 0x64, 0xf5, 0x1c,
+	0x07, 0x64, 0x30, 0x1d,
 	0x08, 0x64, 0xcf, 0x1c,
 	0x11, 0x6a, 0x91, 0x00,
-	0x07, 0x6a, 0x2f, 0x17,
+	0x07, 0x6a, 0x32, 0x17,
 	0xff, 0x06, 0x6a, 0x02,
 	0x00, 0x65, 0x5c, 0x10,
 	0xff, 0xa8, 0xd3, 0x1a,
 	0xff, 0xa2, 0xda, 0x1e,
 	0x01, 0x6a, 0x3d, 0x00,
-	0x00, 0xb9, 0x74, 0x17,
+	0x00, 0xb9, 0x77, 0x17,
 	0xff, 0xa2, 0xda, 0x1e,
 	0x71, 0x6a, 0x91, 0x00,
-	0x40, 0x59, 0xda, 0x18,
+	0x40, 0x5b, 0xda, 0x18,
 	0xff, 0xb9, 0xb3, 0x02,
-	0x00, 0x65, 0xe4, 0x10,
+	0x00, 0x65, 0xe7, 0x10,
 	0x20, 0xa0, 0xe0, 0x1a,
 	0xff, 0x90, 0x4a, 0x02,
 	0xff, 0xb3, 0x49, 0x02,
-	0x00, 0xa1, 0x9e, 0x17,
+	0x00, 0xa1, 0xa1, 0x17,
 	0xff, 0x49, 0x6d, 0x02,
 	0xff, 0x4a, 0x90, 0x02,
+	0xff, 0x5a, 0x64, 0x02,
+	0x00, 0x59, 0xe1, 0x1c,
+	0x01, 0x59, 0x59, 0x06,
 	0xff, 0xb9, 0x9d, 0x02,
 	0x02, 0x6a, 0x91, 0x00,
-	0x08, 0xa0, 0xe4, 0x1e,
+	0x08, 0xa0, 0xe7, 0x1e,
 	0x91, 0x6a, 0x91, 0x00,
-	0xff, 0xb3, 0xf0, 0x1c,
+	0xff, 0xb3, 0xf3, 0x1c,
 	0xff, 0xb3, 0x64, 0x02,
-	0x00, 0xb9, 0xea, 0x1c,
-	0x00, 0x65, 0xa7, 0x17,
+	0x00, 0xb9, 0xed, 0x1c,
+	0x00, 0x65, 0xaa, 0x17,
 	0xff, 0x64, 0x90, 0x02,
-	0x00, 0x65, 0xec, 0x10,
+	0x00, 0x65, 0xef, 0x10,
 	0x0d, 0x6a, 0x3d, 0x00,
-	0x00, 0xb3, 0x74, 0x17,
+	0x00, 0xb3, 0x77, 0x17,
 	0xff, 0x48, 0xba, 0x02,
 	0xff, 0x90, 0x48, 0x02,
 	0x00, 0x65, 0x2f, 0x16,
 	0x00, 0x65, 0x69, 0x10,
-	0x00, 0x65, 0xa7, 0x17,
+	0x00, 0x65, 0xaa, 0x17,
 	0x00, 0x65, 0x69, 0x10,
-	0x4d, 0x6a, 0x37, 0x17,
+	0x4d, 0x6a, 0x3a, 0x17,
 	0xff, 0x4d, 0x64, 0x02,
-	0x00, 0x66, 0x37, 0x17,
+	0x00, 0x66, 0x3a, 0x17,
 	0xff, 0x64, 0x64, 0x06,
-	0x52, 0x66, 0xf8, 0x18,
+	0x52, 0x66, 0xfb, 0x18,
 	0xff, 0x66, 0x66, 0x06,
-	0xff, 0x64, 0xf4, 0x1a,
+	0xff, 0x64, 0xf7, 0x1a,
 	0x41, 0x6a, 0x91, 0x00,
-	0x20, 0x59, 0xcd, 0x1c,
-	0x80, 0x59, 0xcf, 0x18,
+	0x20, 0x5b, 0xcd, 0x1c,
+	0x80, 0x5b, 0xcf, 0x18,
 	0x10, 0x4c, 0x03, 0x00,
 	0x00, 0x65, 0xcf, 0x10,
 	0x04, 0xa0, 0xa0, 0x00,
-	0x00, 0x65, 0xb8, 0x17,
+	0x00, 0x65, 0xbb, 0x17,
 	0x00, 0x65, 0x69, 0x10,
 	0x10, 0x41, 0xcf, 0x1e,
 	0xff, 0x43, 0xa3, 0x02,
 	0xa4, 0x6a, 0x66, 0x00,
-	0x44, 0x6a, 0x70, 0x17,
+	0x44, 0x6a, 0x73, 0x17,
 	0xac, 0x6a, 0x66, 0x00,
-	0x14, 0x6a, 0x70, 0x17,
-	0xa9, 0x6a, 0x71, 0x17,
+	0x14, 0x6a, 0x73, 0x17,
+	0xa9, 0x6a, 0x74, 0x17,
 	0x00, 0x65, 0xcf, 0x10,
 	0xef, 0x41, 0x41, 0x02,
 	0x00, 0x65, 0xcf, 0x10,
 	0x78, 0x64, 0xcd, 0x1a,
 	0x07, 0x64, 0x64, 0x02,
 	0x00, 0x42, 0x42, 0x00,
-	0x00, 0x42, 0x9e, 0x17,
-	0xff, 0x6c, 0x59, 0x02,
-	0xff, 0x59, 0x25, 0x19,
-	0xff, 0x59, 0x15, 0x1d,
-	0xff, 0x59, 0x90, 0x02,
-	0x04, 0xa0, 0x2a, 0x1f,
-	0x00, 0x65, 0x27, 0x11,
+	0x00, 0x42, 0xa1, 0x17,
+	0xff, 0x6c, 0x5b, 0x02,
+	0xff, 0x5b, 0x28, 0x19,
+	0xff, 0x5b, 0x18, 0x1d,
+	0xff, 0x5b, 0x90, 0x02,
+	0x04, 0xa0, 0x2d, 0x1f,
+	0x00, 0x65, 0x2a, 0x11,
 	0xff, 0x06, 0x6a, 0x02,
-	0x01, 0x0c, 0x16, 0x1f,
-	0x04, 0x0c, 0x16, 0x1b,
+	0x01, 0x0c, 0x19, 0x1f,
+	0x04, 0x0c, 0x19, 0x1b,
 	0xe0, 0x03, 0x4c, 0x02,
-	0xe0, 0x4c, 0x2a, 0x19,
-	0x20, 0x12, 0x2a, 0x19,
+	0xe0, 0x4c, 0x2d, 0x19,
+	0x20, 0x12, 0x2d, 0x19,
 	0x20, 0x41, 0x41, 0x00,
-	0x59, 0x6a, 0x37, 0x17,
+	0x5b, 0x6a, 0x3a, 0x17,
 	0xff, 0x3f, 0x64, 0x02,
-	0x00, 0x59, 0x65, 0x06,
-	0x00, 0x65, 0x2a, 0x13,
-	0xff, 0x59, 0x90, 0x02,
+	0x00, 0x5b, 0x65, 0x06,
+	0x00, 0x65, 0x2d, 0x13,
+	0xff, 0x5b, 0x90, 0x02,
 	0xff, 0x42, 0x64, 0x02,
-	0x00, 0xa1, 0x2a, 0x19,
-	0x20, 0xa0, 0x2a, 0x1f,
-	0x04, 0xa0, 0x2a, 0x1f,
-	0x00, 0x6a, 0x4f, 0x17,
-	0xff, 0x65, 0x2a, 0x1d,
+	0x00, 0xa1, 0x2d, 0x19,
+	0x20, 0xa0, 0x2d, 0x1f,
+	0x04, 0xa0, 0x2d, 0x1f,
+	0x00, 0x6a, 0x52, 0x17,
+	0xff, 0x65, 0x2d, 0x1d,
 	0xfb, 0xa0, 0xa0, 0x02,
 	0x40, 0x41, 0x41, 0x00,
 	0x00, 0x65, 0xcf, 0x10,
 	0x31, 0x6a, 0x91, 0x00,
-	0x0c, 0x6a, 0x2f, 0x17,
+	0x0c, 0x6a, 0x32, 0x17,
 	0x00, 0x65, 0xcf, 0x10,
 	0x61, 0x6a, 0x91, 0x00,
 	0x00, 0x65, 0xcf, 0x10,
 	0x50, 0x6a, 0x60, 0x00,
-	0xff, 0x34, 0x33, 0x1f,
+	0xff, 0x34, 0x36, 0x1f,
 	0x10, 0x6a, 0x60, 0x00,
 	0xc1, 0x6a, 0x91, 0x00,
 	0x10, 0x4c, 0x03, 0x00,
@@ -314,50 +317,50 @@
 	0xff, 0x65, 0x35, 0x02,
 	0x10, 0x6a, 0x60, 0x01,
 	0xff, 0x06, 0x6a, 0x02,
-	0x01, 0x0c, 0x38, 0x1f,
-	0x04, 0x0c, 0x38, 0x1b,
+	0x01, 0x0c, 0x3b, 0x1f,
+	0x04, 0x0c, 0x3b, 0x1b,
 	0xe0, 0x03, 0x4c, 0x02,
-	0xe0, 0x4c, 0x3f, 0x19,
+	0xe0, 0x4c, 0x42, 0x19,
 	0xff, 0x65, 0x66, 0x02,
 	0xff, 0x12, 0x6d, 0x03,
 	0xff, 0x06, 0x6a, 0x03,
 	0xd1, 0x6a, 0x91, 0x00,
 	0x00, 0x65, 0x5c, 0x10,
 	0xff, 0x65, 0x93, 0x02,
-	0x01, 0x0b, 0x49, 0x1b,
-	0x10, 0x0c, 0x42, 0x1f,
-	0x04, 0x0b, 0x46, 0x1b,
+	0x01, 0x0b, 0x4c, 0x1b,
+	0x10, 0x0c, 0x45, 0x1f,
+	0x04, 0x0b, 0x49, 0x1b,
 	0xff, 0x6a, 0x65, 0x02,
-	0x04, 0x93, 0x48, 0x1b,
-	0x01, 0x94, 0x47, 0x1f,
-	0x10, 0x94, 0x48, 0x1b,
+	0x04, 0x93, 0x4b, 0x1b,
+	0x01, 0x94, 0x4a, 0x1f,
+	0x10, 0x94, 0x4b, 0x1b,
 	0xc7, 0x93, 0x93, 0x02,
-	0x38, 0x93, 0x4a, 0x1b,
+	0x38, 0x93, 0x4d, 0x1b,
 	0xff, 0x6a, 0x6a, 0x03,
-	0x80, 0x41, 0x4b, 0x1f,
-	0x40, 0x41, 0x4b, 0x1b,
+	0x80, 0x41, 0x4e, 0x1f,
+	0x40, 0x41, 0x4e, 0x1b,
 	0x21, 0x6a, 0x91, 0x01,
 	0xff, 0x65, 0x90, 0x02,
-	0xff, 0x59, 0x64, 0x02,
-	0x00, 0xb9, 0x53, 0x19,
-	0x04, 0xa0, 0x5d, 0x1b,
+	0xff, 0x5b, 0x64, 0x02,
+	0x00, 0xb9, 0x56, 0x19,
+	0x04, 0xa0, 0x60, 0x1b,
 	0x01, 0x65, 0x65, 0x06,
 	0xff, 0x3e, 0x64, 0x02,
-	0x00, 0x65, 0x4f, 0x19,
-	0x00, 0x6a, 0xaa, 0x17,
+	0x00, 0x65, 0x52, 0x19,
+	0x00, 0x6a, 0xad, 0x17,
 	0x0d, 0x6a, 0x3d, 0x00,
-	0x00, 0x59, 0x74, 0x17,
-	0xff, 0xa8, 0x5b, 0x1f,
+	0x00, 0x5b, 0x77, 0x17,
+	0xff, 0xa8, 0x5e, 0x1f,
 	0x10, 0xa0, 0xa0, 0x00,
-	0x08, 0xa0, 0x4b, 0x1f,
+	0x08, 0xa0, 0x4e, 0x1f,
 	0xff, 0x6a, 0x65, 0x01,
-	0x08, 0xa0, 0x5c, 0x1b,
-	0xff, 0xba, 0x63, 0x1d,
+	0x08, 0xa0, 0x5f, 0x1b,
+	0xff, 0xba, 0x66, 0x1d,
 	0xff, 0xbb, 0x49, 0x02,
 	0xff, 0xba, 0x90, 0x02,
 	0xff, 0x49, 0xbb, 0x02,
 	0xff, 0x65, 0x90, 0x02,
-	0xff, 0xbb, 0x68, 0x1d,
+	0xff, 0xbb, 0x6b, 0x1d,
 	0xff, 0xba, 0x49, 0x02,
 	0xff, 0xbb, 0x90, 0x02,
 	0xff, 0x49, 0xba, 0x02,
@@ -386,7 +389,7 @@
 	0xff, 0x6a, 0x8d, 0x02,
 	0xff, 0x6a, 0x8e, 0x02,
 	0xff, 0x3d, 0x93, 0x02,
-	0x04, 0x3d, 0x8c, 0x1b,
+	0x04, 0x3d, 0x8f, 0x1b,
 	0xa0, 0x6a, 0x65, 0x00,
 	0x1c, 0x65, 0x64, 0x06,
 	0xff, 0x6c, 0x99, 0x02,
@@ -396,14 +399,14 @@
 	0xff, 0x6c, 0x99, 0x02,
 	0xff, 0x6c, 0x99, 0x02,
 	0xff, 0x6c, 0x99, 0x02,
-	0x00, 0x65, 0x83, 0x19,
+	0x00, 0x65, 0x86, 0x19,
 	0x0a, 0x93, 0x93, 0x00,
-	0x00, 0x65, 0x9a, 0x17,
-	0x04, 0x3d, 0x4b, 0x1f,
-	0xa0, 0x6a, 0x92, 0x17,
-	0x00, 0x65, 0x93, 0x17,
-	0x00, 0x65, 0x93, 0x17,
-	0x00, 0x65, 0x93, 0x11,
+	0x00, 0x65, 0x9d, 0x17,
+	0x04, 0x3d, 0x4e, 0x1f,
+	0xa0, 0x6a, 0x95, 0x17,
+	0x00, 0x65, 0x96, 0x17,
+	0x00, 0x65, 0x96, 0x17,
+	0x00, 0x65, 0x96, 0x11,
 	0xff, 0x65, 0x66, 0x02,
 	0xff, 0x99, 0x6d, 0x02,
 	0xff, 0x99, 0x6d, 0x02,
@@ -412,40 +415,40 @@
 	0xff, 0x99, 0x6d, 0x02,
 	0xff, 0x99, 0x6d, 0x02,
 	0xff, 0x99, 0x6d, 0x03,
-	0x08, 0x94, 0x9a, 0x1f,
+	0x08, 0x94, 0x9d, 0x1f,
 	0xf7, 0x93, 0x93, 0x02,
-	0x08, 0x93, 0x9c, 0x1b,
+	0x08, 0x93, 0x9f, 0x1b,
 	0xff, 0x6a, 0x6a, 0x03,
 	0xff, 0x65, 0x66, 0x02,
 	0x4c, 0x66, 0x66, 0x0a,
 	0x03, 0x66, 0x66, 0x02,
 	0xbc, 0x66, 0x66, 0x06,
 	0x6a, 0x65, 0x64, 0x0a,
-	0x08, 0x65, 0xa5, 0x1f,
+	0x08, 0x65, 0xa8, 0x1f,
 	0x02, 0x64, 0x64, 0x06,
 	0xff, 0x64, 0x90, 0x02,
 	0xff, 0x66, 0x65, 0x03,
 	0xff, 0x53, 0xba, 0x02,
 	0xff, 0x6a, 0xb9, 0x00,
 	0xff, 0x90, 0x53, 0x03,
-	0xff, 0x53, 0xb6, 0x19,
-	0xff, 0x52, 0xad, 0x19,
+	0xff, 0x53, 0xb9, 0x19,
+	0xff, 0x52, 0xb0, 0x19,
 	0xff, 0x6a, 0x65, 0x01,
 	0xff, 0x52, 0x90, 0x02,
-	0x10, 0xa0, 0xb1, 0x1f,
+	0x10, 0xa0, 0xb4, 0x1f,
 	0xef, 0xa0, 0xa0, 0x02,
-	0x00, 0x65, 0xb3, 0x11,
-	0xff, 0xa8, 0xb3, 0x1b,
-	0xff, 0xb3, 0xb5, 0x1d,
+	0x00, 0x65, 0xb6, 0x11,
+	0xff, 0xa8, 0xb6, 0x1b,
+	0xff, 0xb3, 0xb8, 0x1d,
 	0x01, 0x6a, 0x3d, 0x00,
-	0x00, 0xb9, 0x74, 0x17,
-	0x00, 0x90, 0x5e, 0x11,
+	0x00, 0xb9, 0x77, 0x17,
+	0x00, 0x90, 0x61, 0x11,
 	0xff, 0x53, 0x90, 0x02,
 	0xff, 0xba, 0x53, 0x03,
 	0xff, 0x6a, 0xbb, 0x00,
 	0xff, 0x52, 0xba, 0x02,
 	0xff, 0x90, 0x52, 0x02,
-	0xff, 0xba, 0x4b, 0x1d,
+	0xff, 0xba, 0x4e, 0x1d,
 	0xff, 0xba, 0x90, 0x02,
 	0xff, 0x52, 0xbb, 0x02,
 	0xff, 0x52, 0x90, 0x03,
@@ -466,14 +469,15 @@
 	{ 0x00000004, 1, 0x023, 0x027 },
 	{ 0x00000002, 0, 0x02f, 0x033 },
 	{ 0x00000008, 0, 0x04f, 0x056 },
-	{ 0x00000004, 1, 0x0e5, 0x0ea },
-	{ 0x00000004, 0, 0x0ff, 0x100 },
-	{ 0x00000004, 0, 0x110, 0x111 },
-	{ 0x00000004, 1, 0x111, 0x115 },
-	{ 0x00000004, 1, 0x120, 0x125 },
-	{ 0x00000004, 0, 0x125, 0x127 },
-	{ 0x00000004, 0, 0x14f, 0x169 },
-	{ 0x00000004, 1, 0x169, 0x16a },
-	{ 0x00000004, 0, 0x1aa, 0x1bf },
+	{ 0x00000004, 0, 0x0e0, 0x0e3 },
+	{ 0x00000004, 1, 0x0e8, 0x0ed },
+	{ 0x00000004, 0, 0x102, 0x103 },
+	{ 0x00000004, 0, 0x113, 0x114 },
+	{ 0x00000004, 1, 0x114, 0x118 },
+	{ 0x00000004, 1, 0x123, 0x128 },
+	{ 0x00000004, 0, 0x128, 0x12a },
+	{ 0x00000004, 0, 0x152, 0x16c },
+	{ 0x00000004, 1, 0x16c, 0x16d },
+	{ 0x00000004, 0, 0x1ad, 0x1c2 },
 	{ 0x00000000, 0, 0x000, 0x000 }
 };
diff -urN linux-2.0.31-pre5/drivers/scsi/ChangeLog.ncr53c8xx linux-2.0.31-pre6/drivers/scsi/ChangeLog.ncr53c8xx
--- linux-2.0.31-pre5/drivers/scsi/ChangeLog.ncr53c8xx	1996-08-31 23:15:32.000000000 -0700
+++ linux-2.0.31-pre6/drivers/scsi/ChangeLog.ncr53c8xx	2003-08-15 15:04:01.000000000 -0700
@@ -1,3 +1,421 @@
+Sat July 26 18:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.4
+	Several clean-ups:
+	  - Asynchronous pre-scaler calculation.
+	    Synchronous divisor calculation.
+	  - Use FE_ as feature identifier prefix instead of _F_.
+	  - Change 'ns_sync' identifier to "minsync".
+	  - Some others.
+	Apply some SPI2-R12 recommendations.
+	  - Use Slow, Fast-10, Fast-20, Fast-40 SCSI instead of SCSI-2, 
+	    FAST SCSI-2, ULTRA, ULTRA-2. 
+	  - Reset the SCSI on bus mode change.
+
+Wed July 02 22:58 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.3c
+	- Add define SCSI_NCR_PCI_FIX_UP_SUPPORT for conditionnal compilation 
+	  of the corresponding pci fix-up code when a small driver is needed.
+	- Use "ncr53c8xx" as driver name for both request_irq() and 
+          request_region(). Using different names confused 'lsdev'.
+          (Suggestion sent by Henrik Storner).
+
+Wed June 24 22:08 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.3b
+	- Print an error message on unexpected boot command line option.
+	- Switch to asynchronous data transfer mode after SCSI wide 
+	  negotiation.
+
+Wed June 24 22:08 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.3b
+	- Print an error message on unexpected boot command line option.
+	- Switch to asynchronous data transfer mode after SCSI wide 
+	  negotiation.
+
+Wed June 14 22:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.3a
+	- Add PCI LATENCY TIMER fixup code.
+	  Increase it if necessary according to burst size.
+	  Boot option bit : 'pcifix:4'
+	- On phase mismatch, calculate residual data size for all OUTPUT 
+	  phases. That's only required for interrupted DATA OUT phase, but 
+	  this information is usefull for problem solving.
+	- Add KERN_INFO to some messages printed to the log.
+	  (Patch sent by Wolfram Kleff).
+
+Tue June 02 22:30 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.3
+	- NvRAM support code slightly improved (I think):
+	  Use IO or MMIO according to driver setup for reading the NvRAM.
+	  Use structures for NvRAM data instead of raw data.
+	- Prevent from queuing more than 1 command to the scsi SCRIPT with 
+	  negotiation attached when tagged command queueing is enabled.
+	- Fix-up for old 53C8XX chips that support PCI READ LINE but not 
+	  CACHE LINE SIZE. If the cache line size is unknown, set burst 
+	  to 8 dwords and disable READ LINE, otherwise set burst max to 
+	  the cache line size value.
+
+Sat May 24 12:30 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.2c (for linux-2.1.40)
+	- Remove reference to 'x86' symbol when MODULE is defined, since this 
+	  symbol is not exported for module loading.
+	  The value of 'x86' is used for fixing up the PCI CACHE LINE SIZE 
+	  configuration register.
+	- Bytes/words read one bit at a time from the serial NVRAM were'nt 
+          initialized with zero.
+	- Some comments added. Minor cosmetic changes.
+
+Mon May 19 20:30 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.2b
+	- Patch for NVRAM support by Richard Waltham applied.
+	  The code detects Symbios NVRAM format and Tekram NVRAM format. 
+	  This enhancement allows to get hosts and devices user set up 
+	  from the NVRAM.
+	- Use the NVRAM contents when present to initialize user definable 
+	  target parameters.
+	- Update the README file. 
+
+Sun May 11 22:30 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.1b
+	- Cosmetic changes.
+	- Some heavy testings under pre-linux-2.1.37-6
+
+Sun May 4 22:30 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.1a
+	- PFEN wrongly used for PREFETCH feature bit testing.
+	  Changed to _F_PFEN.
+	- 2 SCR_COPY that need NO FLUSH bit to be removed had been missed 
+	  in tp->getscr[] script (loads SXFER and SCNTL3 on reselection).
+
+Sat May 3 22:30 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.1
+	- Use the NO FLUSH option for MOVE MEMORY (COPY) each time it is 
+	  possible. More than 100 COPY with NO FLUSH and 6 with FLUSH for  
+	  my configuration (max queued command / device = 8).
+	  This option bit is removed from the script instance for chips 
+	  that donnot support prefetching.
+	- Rewrite the ncr_exception() routine more simple (I think) and 
+	  remove useless code.
+	- Change the data_in and data_out script management.
+	  Use the bottom part of these scripts instead of the beginning.
+	  That avoids to zero the scatter/gather array when a command is 
+	  queued (1k) and to deal with some weird IID on MOVE 0 bytes when 
+	  a target wants to transfer more bytes than expected.
+	- Misc. improvements in the init code.
+	- Remove IOMAPPED/MMIO automatic switching option.
+	  Was useless and reported not reliable.
+	- Fix a double read of DSTAT and remove DFE testing in the 
+	  Phase mismatch service routine.
+	- Etc...
+
+Fri Apr 26 20:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.0a
+	- Add support if the Diamond FirePort 40 (SYM53C875J chip)
+
+Mon Apr 22 22:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 2.0
+	- incorporate __initdata and __initfunc directives in order to 
+	  allow 'init' to free unused memory after driver initialisations.
+	  Patch sent by Roberto Fichera.
+	- rewrite the init code of the driver. Now a feature descriptor 
+	  is used for each real chip types. The code is a lot more clean,
+	  since the driver uses device and revision ids only in the 
+	  detection procedure.
+	- add 'pcifix' boot command line. This command allows to fix up PCI 
+	  config space for new chips which support features based on the 
+	  cache line size and 'write and invalidate'.
+	- incorporate in the driver, the code used for error recovery  
+	  testing. This code is normally not compiled; have to define 
+	  SCSI_NCR_DEBUG_ERROR_RECOVERY in order to compile it.
+	- take into account actual SCSI bus mode for 53C895 LVD/SE controller.
+	  In single ended mode only fast20 is supported.
+          (Just to not be late since such controllers are not yet available)
+          
+
+Sat Apr 20 21:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 1.18f
+	- fix an old bug included in the initial port (version 0.0).
+	  The driver allocated 10 bytes of static data and uses 12 bytes.
+	  No danger, since data are generally aligned on 4 bytes boundary 
+	  and so byte 10 and 11 are free (I hope ...)
+
+Wed Apr 16 12:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 1.18e
+	- reset all when an unexpected data cycle is detected while 
+	  disconnecting.
+	- make changes to abort() ans reset() functions according to 
+	  Leonard's documentation.
+	- small fix in some message for hard errors.
+
+Sat Apr 5  13:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 1.18d
+	- Probe NCR pci device ids in reverse order if asked by user from 
+	  the boot command line. Suggested by Richard Waltham.
+	- Make a separate function that prints out verbose information on 
+	  severe error (assumed from hardware).
+	- Add the transfer period factor and the max commands per lun value 
+	  to the proc info data. If debug flags are set or verbosity is 
+	  greater than 1, debug flags and verbosity are returned in proc  
+	  info data.
+	- Update the documentation.
+
+Thu Mar 20 23:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* revision 1.18c
+	- Add special features support for NCR53C885 and NCR53C896 chip.
+	  Quite obvious, but untested, and based on the fact that:
+	  The 885 supports same features as the 875.
+	  The 896 is a 64 bits PCI version of the 895.
+	- Improve recovery from SCSI GROSS ERRORS.
+	  I can get such errors by making the driver negotiate offset 8 with 
+	  a disk and setting the ncr chip to a lower offset value.
+	  I got bunches of errors that have been gracefully recovered by 
+	  the driver.
+	  The driver now uses its timer handler in order to wait 2 sec. for 
+	  devices to settle after SCSI reset and so does not uselessly freeze 
+	  the system with interrupt masked for seconds.
+	- Enable 'burst op code fetch' and 'read line' for 815 chips.
+	- Use a 2 commands queue depth instead of 1 for devices that does 
+          not support tagged command queuing.
+	- The ULTRA timing flag setting was based on the output resulting 
+	  period factor of the ncr and not on the negotiated one.
+	  This flag setting was wrong only for 24 ns negotiated period factor.
+	- Some other minor changes and cleanups.
+
+Thu Feb 27 23:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c ncr53c8xx.h revision 1.18b
+	- 'On paper' support of the NCR53C895 Ultra-2 chip.
+	  (Clock quadrupler + 7 clock divisors)
+	- Load the main part of the script into the on-board RAM.
+	- 810A rev. 0x11 PCI problem fixed.
+	  This chip is now supported with all PCI features enabled and 
+	  16 dwords burst transfers. 
+	- Align on 32 boundary some internal structures.
+	  That fixes the 810A problem and allows cache line bursting when 
+	  moving the global header (64 bytes) from/to CCBs to/from NCB.
+	- Synchronous parameters calculation rewritten. The driver 
+	  now uses all available clock divisors and will be able to support 
+          clock frequencies that are not multiple of 40 Mhz if necessary.
+
+Sat Feb 8 22:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c - revision 1.17a
+	- IRQ mode set up from boot setup command.
+	  irqm:0    open drain (default)
+	  irqm:1    preserve initial setting (assumed from BIOS)
+	  irqm:2    totem pole
+	- DIFF mode set up from boot setup command.
+	  Suggested by Richard Waltham.
+	  diff:0    never set up diff mode (default)
+	  diff:1    set up diff mode according to initial setting (BIOS?)
+	  diff:2    always set up diff mode
+	  diff:3    set up diff mode if GPIO3 is zero (SYMBIOS boards)
+	- Change CONFIG option for LED support.
+          CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT allows LED support and 
+	  DIFF support for SYMBIOS boards and compatibles (clones?).
+	- Set 16 DWORD bursts for 810A rev. >= 0x12 since my SC200 with 
+	  such a chip have no problem with it (MB with Triton 2 HX).
+	  810A rev. 0x11 are set to 8 DWORD bursts since they may give
+	  problems with PCI read multiple and Triton 2 HX.
+	  Thanks to Stefan for this information.
+
+Sat Jan 25 22:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c - revision 1.17
+	- Controller LED support.
+	  Only works with LED pin wired to GPIO_FETCHN, so probably with 
+          all boards using SMDS BIOS.
+	  This option can be enabled only if CONFIG_EXPERIMENTAL is set.
+	- Assume clock doubler for 875 chip when clock frequency measurement 
+	  result is 40 MHz. May help when some old stuff as SDMS BIOS 3.0 
+	  or some old driver has broken the normal BIOS settings.
+	- Add wide negotiation control from boot setup command.
+	  May be usefull with systems using a 875 based board connected to 
+	  a wide device through a 50 pins to 68 pins converter.
+	- Add a "boot fail safe option" to the boot setup command line.
+	- Rewrite the "reset_command" routine.
+	  Low-level driver are responsible to keep the involved command 
+	  alive. The new code seems to behave correctly.
+	- Change some variables used by the script from u_long to u_int32.
+	- Remove some useless code.
+
+Sun Jan 12 12:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c - revision 1.16e
+	- Add support of PCI burst length control from boot setup command.
+	  burst:0     disable burst
+	  burst:255   get burst from initial settings (BIOS settings?)
+	  burst:#x    set burst transfers to 1<<#x
+	- Only check xfer direction for common op-codes.
+	  For all device specific / vendor specific opcodes the driver 
+	  now uses the xfer direction decided by the target.
+
+Sun Jan 05 12:00 1997 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c - revision 1.16d
+	- The driver is now able to process scsi commands without 
+	  knowledge of xfer data direction.
+	  Stefan agreed with this change for Linux. This change is 
+	  not needed under FreeBSD since low-level drivers receive 
+	  the expected data direction for each scsi request.
+	- Save ctest5 features bits at start-up and restore them at 
+	  module release step.
+	  Avoid side effects when a ncr driver which trusts bios 
+	  settings is reloaded (could be the ncr53c8xx itself).
+
+
+Wed Jan 01 23:30 1997 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c - revision 1.16c
+	- Bad decision about 20MHz for 13 ns period factor.
+	  Was wrong, so I restore the previous algorithm.
+	- Burst length 128 not correctly set in dmode.
+
+Thu Dec 26 22:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c ncr53c8xx.h README.ncr53c8xx - revision 1.16b
+	- Remove useless code.
+	- Try to improve error recovery in case of abort and reset.
+	- Remove DEBUG_NEGO by default.
+	- Add boot setup command support.
+	  Now, all experimental config options can be removed.
+	- Update README file.
+
+
+Mon Dec 23 23:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c ncr53c8xx.h - revision 1.16a
+	New display for speed ##.# MB/s (From Stefan)
+	- I add "WIDE" qualifier after ULTRA and FAST
+	- I get "FAST WIDE SCSI-2 20 MB/s" with my Atlas. That's nice.
+
+	Richard Waltham reports SYMBIOS set the 875 to 20 MB/s for 13 ns 
+	period factor. I decide to trust SYMBIOS. 20 MB/s output speed 
+	instead of 19.2 MB/s should not cause problem. The ncr is only able 
+	to use 16.67 MB/s when 20 MB/s is not possible.
+
+	Fix from Markus Kossman: "Ultra SCSI enabled" wrongly printed 
+	when not enabled.
+
+	Set DEBUG_NEGO by default in order to get reports about sync nego. 
+	Will remove it in the next patch.
+
+Thu Dec 19 21:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c ncr53c8xx.h README.ncr53c8xx - revision 1.16
+	Incorporate new definitions in ncr53c8xx.h (From Stefan).
+	Check changes against Stefan's current version of the driver.
+	All seems ok.
+
+Sat Nov 30 21:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c ncr53c8xx.h
+	Make changes in order to support: 
+	- Clock doubler and so 80 Mhz scsi clock for 875 chips.
+	- Sync transfers below 7.5 MB/sec.
+          Use Clock/2 between 5 and 10 Mega-transfers/s and Clock/4 below 5.
+	- Ultra SCSI data transfers.
+	- Offset 16.
+
+	Works with my configuration. However I cannot test Ultra transfers,
+	since my disks are only fast scsi-2.
+
+Tue Nov 28 21:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	I received yesterday my Promise SCSI Ultra board.
+	NCR53C875 rev. 3 with clock doubler.
+	Add the code to support some bus features, the large 536 dma fifo and 
+	burst 128. Works.
+
+Mon Nov 4 21:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c ncr53c8xx.h - revision 1.14c
+	Severall control command improvements:
+
+	- Allow to specify "all" to commands that apply to #target.
+	  For example: "setsync all 255" sets asynchronous data 
+	               transfers for all targets on a bus.
+
+	- Allow to control disconnection privilege per device, as follow:
+	  "setflag #target no_sync" disables disconnection for #target.
+	  "setflag #target" with no flag specified reenables it.
+
+	  Obviously #target may be specified as "all" in order to control 
+	  disconnection for all targets with a single control command.
+
+	- README file updated and some hints about SCSI problems solving added.
+
+Sun Oct 27 22:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c ncr53c8xx.h - revision 1.14b
+	Add the following config parameters:
+
+	- CONFIG_SCSI_NCR53C8XX_MAX_TAGS
+	  Max number of queued tagged commands.
+	  Allow from 2 to 12, default 4.
+
+	- CONFIG_SCSI_NCR53C8XX_SYNC
+	  Synchronous transfers frequency in MHz.
+	  Allow from 5 to 10, default 5, 0 means asynchronous.
+	  (And so remove CONFIG_SCSI_NCR53C8XX_FORCE_ASYNCHRONOUS)
+
+Sun Oct 20 16:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	ncr_scatter() rewritten.
+	remove "ncr dead" detection.
+ 
+Sun Oct 13 19:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c ncr53c8xx.h - revision 1.14a
+	Enabling some special features makes problems with some hardware.
+	So, disable them by default.
+	Add SCSI_NCR_SPECIAL_FEATURES define to play with.
+ 
+Sun Oct 13 14:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c ncr53c8xx.h
+	Incorporate Stefan's patch for clock frequency detection.
+	(Committed in FreeBSD/ncr.c rev. 1.81).
+	The driver then does about the following:
+	    Assume 40 MHz clock for all ncr chips except:
+	    - NCR53C860 chips:
+	        Assume 80 Mhz clock.
+	    - NCR53C875 chips:
+	        If clock doubler enabled, disable it and assume 40 Mhz clock.
+	        Else if (scntl3&7)=0 measure scsi clock frequency.
+	        Else trust bios setting of scntl3&7 (3=40 Mhz, 5=80Mhz).
+
+Wed Oct 9 22:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c - release 1.14
+	For now, just change the clock detection as follow:
+	- If clock doubler selected by BIOS, assume 40 MHz clock since 
+	  clock doubler will be disabled by chip reset.
+	- Else if NCR53C860 assume 80 MHz clock.
+	- Else trust BIOS setting if (scntl3&7 >= 3)
+	- Else assume 40 MHz clock.
+
+Sat Oct 05  17:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	Stefan sent me a patch that improves the clock frequency detection 
+	of the driver. Stefan uses the general timer register stime1 in 
+	order to measure as accurately as possible the scsi clock.
+	Works ok with my 825, but needs still testing. So will be 
+	released later.
+
+Sun Sep 29  17:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	Preserve dcntl/dmode/ctest3/ctest4 features bits at start-up.
+	Add the define option SCSI_NCR_TRUST_BIOS_SETTING.
+	- If this option is defined, the driver will preserve the 
+	  corresponding bits of io registers.
+	- Else, the driver will set features bits according to chip 
+	  and revision ids.
+
+Sun Sep 22  17:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	Remove useless fields and code and so spare cpu:
+	- profile data are accumulated in jiffies ticks and converted 
+	  to milli-seconds when read through proc fs.
+	- when IOMAPPED is not defined, try only MMIO.
+	  (avoid testing a value in order to choose between IO and MMIO)
+
+Sun Sep 01  20:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.h, ncr53c8xx.c - Version 1.13
+	Adaptation of the tagged command queuing depth control of the 
+	FreeBSD driver to Linux. Now, tagged command queueing can be 
+	disabled at run time by a "settags N 0" control command.
+	Add the following heuristic in order to manage intelligently (perhaps) 
+	QUEUE_FULL status:
+	- Each time a QUEUE FULL status is returned by a device, disable tagged 
+	  command queuing for that device.
+	- Every 100 successfully complete commands, increment the maximum 
+	  queuable commands (up to the allowed limit).
+
 Fri Aug 30  10:00 1996 Gerard Roudier (groudier@club-internet.fr)
 	* ncr53c8xx.c - Version 1.12c
 	Incorporate the changes of FreeBSD/ncr.c revision 1.76.
diff -urN linux-2.0.31-pre5/drivers/scsi/Config.in linux-2.0.31-pre6/drivers/scsi/Config.in
--- linux-2.0.31-pre5/drivers/scsi/Config.in	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/drivers/scsi/Config.in	2003-08-15 15:04:01.000000000 -0700
@@ -21,10 +21,13 @@
 dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
 if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
     bool '   Enable tagged command queueing' CONFIG_AIC7XXX_TAGGED_QUEUEING Y
-    int  '   Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8
+    dep_tristate '   Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N
+    if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then
+      int  '   Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8
+    fi
     bool '   Enable SCB paging' CONFIG_AIC7XXX_PAGE_ENABLE N
     bool '   Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
-    int  '   delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 15
+    int  '   Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 15
 fi
 dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
 dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
@@ -62,15 +65,17 @@
 if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_NCR53C7xx" != "y" ]; then
   dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
   if [ "$CONFIG_SCSI_NCR53C8XX" != "n" ]; then
+    bool '  detect and read serial NVRAMs' CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT
     bool '  enable tagged command queueing' CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE
-    bool '  force normal IO' CONFIG_SCSI_NCR53C8XX_IOMAPPED
-    bool '  not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
-    bool '  force asynchronous transfer mode' CONFIG_SCSI_NCR53C8XX_FORCE_ASYNCHRONOUS
-    bool '  force synchronous negotiation' CONFIG_SCSI_NCR53C8XX_FORCE_SYNC_NEGO
-  fi
-  if [ "$CONFIG_SCSI_NCR53C8XX" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    bool '  disable master parity checking' CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK
-    bool '  disable scsi parity checking' CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK
+    bool '  use normal IO' CONFIG_SCSI_NCR53C8XX_IOMAPPED
+    int  '  maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 4
+    int  '  synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 5
+    if [ "$CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE" != "y" ]; then
+      bool '  not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
+    fi
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      bool '  assume boards are SYMBIOS compatible' CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
+    fi
   fi
 fi
 dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI
@@ -80,6 +85,9 @@
   dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
 fi
 dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI
+if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_AM53C974" != "y" ]; then
+  dep_tristate 'Tekram DC-390(T) SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI
+fi
 dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI
 dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI
   if [ "$CONFIG_SCSI_U14_34F" != "n" ]; then
diff -urN linux-2.0.31-pre5/drivers/scsi/dc390.h linux-2.0.31-pre6/drivers/scsi/dc390.h
--- linux-2.0.31-pre5/drivers/scsi/dc390.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre6/drivers/scsi/dc390.h	2003-08-15 15:04:01.000000000 -0700
@@ -0,0 +1,147 @@
+/***********************************************************************
+ *	FILE NAME : DC390.H					       *
+ *	     BY   : C.L. Huang					       *
+ *	Description: Device Driver for Tekram DC-390(T) PCI SCSI       *
+ *		     Bus Master Host Adapter			       *
+ ***********************************************************************/
+
+/* Kernel version autodetection */
+
+#include <linux/version.h>
+/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */
+#define ASC_LINUX_VERSION(V, P, S)	(((V) * 65536) + ((P) * 256) + (S))
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,50)
+#define VERSION_ELF_1_2_13
+#elseif LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,95)
+#define VERSION_1_3_85
+#else
+#define VERSION_2_0_0
+#endif
+
+/*
+ * AMD 53C974 driver, header file
+ */
+
+#ifndef DC390_H
+#define DC390_H
+
+#if defined(HOSTS_C) || defined(MODULE)
+
+#ifdef	VERSION_2_0_0
+#include <scsi/scsicam.h>
+#else
+#include <linux/scsicam.h>
+#endif
+
+extern int DC390_detect(Scsi_Host_Template *psht);
+extern int DC390_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
+extern int DC390_abort(Scsi_Cmnd *cmd);
+
+#ifdef	VERSION_2_0_0
+extern int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags);
+#else
+extern int DC390_reset(Scsi_Cmnd *cmd);
+#endif
+
+#ifdef	VERSION_ELF_1_2_13
+extern int DC390_bios_param(Disk *disk, int devno, int geom[]);
+#else
+extern int DC390_bios_param(Disk *disk, kdev_t devno, int geom[]);
+#endif
+
+#ifdef MODULE
+static int DC390_release(struct Scsi_Host *);
+#else
+#define DC390_release NULL
+#endif
+
+#ifndef VERSION_ELF_1_2_13
+extern struct proc_dir_entry proc_scsi_tmscsim;
+extern int tmscsim_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
+#endif
+
+#ifdef	VERSION_2_0_0
+
+#define DC390_T    {			\
+	NULL,	/* *next */		\
+	NULL,	/* *usage_count */	\
+	&proc_scsi_tmscsim,	/* *proc_dir */ 	\
+	tmscsim_proc_info,	/* (*proc_info)() */	\
+	"Tekram DC390(T) V1.10 Dec-05-1996",  /* *name */ \
+	DC390_detect,			\
+	DC390_release,	/* (*release)() */	\
+	NULL,	/* *(*info)() */	\
+	NULL,	/* (*command)() */	\
+	DC390_queue_command,	\
+	DC390_abort,		\
+	DC390_reset,		\
+	NULL, /* slave attach */\
+	DC390_bios_param,	\
+	10,/* can queue(-1) */	\
+	7, /* id(-1) */ 	\
+	SG_ALL, 		\
+	2, /* cmd per lun(2) */ \
+	0, /* present */	\
+	0, /* unchecked isa dma */ \
+	DISABLE_CLUSTERING	\
+	}
+#endif
+
+
+#ifdef	VERSION_1_3_85
+
+#define DC390_T    {			\
+	NULL,	/* *next */		\
+	NULL,	/* *usage_count */	\
+	&proc_scsi_tmscsim,	/* *proc_dir */ 	\
+	tmscsim_proc_info,	/* (*proc_info)() */	\
+	"Tekram DC390(T) V1.10 Dec-05-1996",  /* *name */ \
+	DC390_detect,			\
+	DC390_release,	/* (*release)() */	\
+	NULL,	/* *(*info)() */	\
+	NULL,	/* (*command)() */	\
+	DC390_queue_command,	\
+	DC390_abort,		\
+	DC390_reset,		\
+	NULL, /* slave attach */\
+	DC390_bios_param,	\
+	10,/* can queue(-1) */	\
+	7, /* id(-1) */ 	\
+	SG_ALL, 		\
+	2, /* cmd per lun(2) */ \
+	0, /* present */	\
+	0, /* unchecked isa dma */ \
+	DISABLE_CLUSTERING	\
+	}
+#endif
+
+
+#ifdef	VERSION_ELF_1_2_13
+
+#define DC390_T     {		\
+	NULL,			\
+	NULL,			\
+	"Tekram DC390(T) V1.10 Dec-05-1996",\
+	DC390_detect,		\
+	DC390_release,			\
+	NULL, /* info */	\
+	NULL, /* command, deprecated */ \
+	DC390_queue_command,	\
+	DC390_abort,		\
+	DC390_reset,		\
+	NULL, /* slave attach */\
+	DC390_bios_param,	\
+	10,/* can queue(-1) */	\
+	7, /* id(-1) */ 	\
+	16,/* old (SG_ALL) */	\
+	2, /* cmd per lun(2) */ \
+	0, /* present */	\
+	0, /* unchecked isa dma */ \
+	DISABLE_CLUSTERING	\
+	}
+#endif
+
+#endif /* defined(HOSTS_C) || defined(MODULE) */
+
+#endif /* DC390_H */
diff -urN linux-2.0.31-pre5/drivers/scsi/hosts.c linux-2.0.31-pre6/drivers/scsi/hosts.c
--- linux-2.0.31-pre5/drivers/scsi/hosts.c	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/drivers/scsi/hosts.c	2003-08-15 15:04:01.000000000 -0700
@@ -153,6 +153,10 @@
 #include "NCR53c406a.h"
 #endif
 
+#ifdef CONFIG_SCSI_DC390T
+#include "dc390.h"
+#endif
+
 #ifdef CONFIG_SCSI_AM53C974
 #include "AM53C974.h"
 #endif
@@ -284,6 +288,9 @@
 #ifdef CONFIG_SCSI_DTC3280
         DTC3x80,
 #endif
+#ifdef CONFIG_SCSI_DC390T
+    DC390_T,
+#endif
 #ifdef CONFIG_SCSI_NCR53C7xx
     NCR53c7xx,
 #endif
diff -urN linux-2.0.31-pre5/drivers/scsi/Makefile linux-2.0.31-pre6/drivers/scsi/Makefile
--- linux-2.0.31-pre5/drivers/scsi/Makefile	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/drivers/scsi/Makefile	2003-08-15 15:04:01.000000000 -0700
@@ -178,6 +178,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_SCSI_DC390T),y)
+L_OBJS += tmscsim.o
+else
+  ifeq ($(CONFIG_SCSI_DC390T),m)
+  M_OBJS += tmscsim.o
+  endif
+endif
+
 ifeq ($(CONFIG_SCSI_AM53C974),y)
 L_OBJS += AM53C974.o
 else
@@ -380,6 +388,9 @@
 seagate.o: seagate.c
 	$(CC) $(CFLAGS) -DARBITRATE -DSLOW_HANDSHAKE -DFAST32 -c seagate.c 
 
+tmscsim.o : tmscsim.c
+	$(CC) $(CFLAGS) -c tmscsim.c
+
 53c8xx_d.h 53c8xx_u.h : 53c7,8xx.scr script_asm.pl
 	ln -sf 53c7,8xx.scr fake.c
 	$(CPP) -traditional -DCHIP=810 fake.c | grep -v '^#' | perl script_asm.pl 
diff -urN linux-2.0.31-pre5/drivers/scsi/ncr53c8xx.c linux-2.0.31-pre6/drivers/scsi/ncr53c8xx.c
--- linux-2.0.31-pre5/drivers/scsi/ncr53c8xx.c	1996-12-11 07:02:43.000000000 -0800
+++ linux-2.0.31-pre6/drivers/scsi/ncr53c8xx.c	2003-08-15 15:04:01.000000000 -0700
@@ -36,11 +36,35 @@
 **  And has been ported to NetBSD by
 **          Charles M. Hannum           <mycroft@gnu.ai.mit.edu>
 **
+**-----------------------------------------------------------------------------
+**
+**                     Brief history
+**
+**  December 10 1995 by Gerard Roudier:
+**     Initial port to Linux.
+**
+**  June 23 1996 by Gerard Roudier:
+**     Support for 64 bits architectures (Alpha).
+**
+**  November 30 1996 by Gerard Roudier:
+**     Support for Fast-20 scsi.
+**     Support for large DMA fifo and 128 dwords bursting.
+**
+**  February 27 1997 by Gerard Roudier:
+**     Support for Fast-40 scsi.
+**     Support for on-Board RAM.
+**
+**  May 3 1997 by Gerard Roudier:
+**     Full support for scsi scripts instructions pre-fetching.
+**
+**  May 19 1997 by Richard Waltham <dormouse@farsrobt.demon.co.uk>:
+**     Support for NvRAM detection and reading.
+**
 *******************************************************************************
 */
 
 /*
-**	30 August 1996, version 1.12c
+**	26 July 1997, version 2.4
 **
 **	Supported SCSI-II features:
 **	    Synchronous negotiation
@@ -51,26 +75,22 @@
 **	    Etc...
 **
 **	Supported NCR chips:
-**		53C810		(NCR BIOS in flash-bios required) 
-**		53C815		(~53C810 with on board rom BIOS)
-**		53C820		(Wide, NCR BIOS in flash bios required)
-**		53C825		(Wide, ~53C820 with on board rom BIOS)
-**		53C860		(not yet tested)
-**		53C875		(not yet tested)
+**		53C810		(8 bits, Fast SCSI-2, no rom BIOS) 
+**		53C815		(8 bits, Fast SCSI-2, on board rom BIOS)
+**		53C820		(Wide,   Fast SCSI-2, no rom BIOS)
+**		53C825		(Wide,   Fast SCSI-2, on board rom BIOS)
+**		53C860		(8 bits, Fast 20,     no rom BIOS)
+**		53C875		(Wide,   Fast 20,     on board rom BIOS)
+**		53C895		(Wide,   Fast 40,     on board rom BIOS)
 **
 **	Other features:
-**		Memory mapped IO (linux-1.3.X only)
+**		Memory mapped IO (linux-1.3.X and above only)
 **		Module
 **		Shared IRQ (since linux-1.3.72)
 */
 
-#define SCSI_NCR_DEBUG
 #define SCSI_NCR_DEBUG_FLAGS	(0)		
 
-#define NCR_DATE "pl23 95/09/07"
-
-#define NCR_VERSION	(2)
-
 #define NCR_GETCC_WITHMSG
 
 /*==========================================================
@@ -105,11 +125,22 @@
 
 #include <linux/version.h>
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
-#include "linux/blk.h"
+#include <linux/blk.h>
 #else
 #include "../block/blk.h"
 #endif
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35)
+#include <linux/init.h>
+#else
+#ifndef	__initdata
+#define	__initdata
+#endif
+#ifndef	__initfunc
+#define	__initfunc(__arginit) __arginit
+#endif
+#endif
+
 #include "scsi.h"
 #include "hosts.h"
 #include "constants.h"
@@ -132,15 +163,6 @@
 */
 
 /*
-**	Proc info and user command support
-*/
-
-#ifdef SCSI_NCR_PROC_INFO_SUPPORT
-#define SCSI_NCR_PROFILE
-#define SCSI_NCR_USER_COMMAND
-#endif
-
-/*
 **    SCSI address of this device.
 **    The boot routines should have set it.
 **    If not, use this.
@@ -151,24 +173,6 @@
 #endif
 
 /*
-**    The maximal synchronous frequency in kHz.
-**    (0=asynchronous)
-*/
-
-#ifndef SCSI_NCR_MAX_SYNC
-#define SCSI_NCR_MAX_SYNC   (10000)
-#endif
-
-/*
-**    The maximal bus with (in log2 byte)
-**    (0=8 bit, 1=16 bit)
-*/
-
-#ifndef SCSI_NCR_MAX_WIDE
-#define SCSI_NCR_MAX_WIDE   (1)
-#endif
-
-/*
 **    The maximum number of tags per logic unit.
 **    Used only for disk devices that support tags.
 */
@@ -177,13 +181,6 @@
 #define SCSI_NCR_MAX_TAGS    (4)
 #endif
 
-/*==========================================================
-**
-**      Configuration and Debugging
-**
-**==========================================================
-*/
-
 /*
 **    Number of targets supported by the driver.
 **    n permits target numbers 0..n-1.
@@ -209,7 +206,14 @@
 #else
 #define MAX_LUN    (1)
 #endif
+
+/*
+**    Asynchronous pre-scaler (ns). Shall be 40
+*/
  
+#ifndef SCSI_NCR_MIN_ASYNC
+#define SCSI_NCR_MIN_ASYNC (40)
+#endif
 
 /*
 **    The maximum number of jobs scheduled for starting.
@@ -231,12 +235,11 @@
 #define MAX_SCATTER (SCSI_NCR_MAX_SCATTER)
 
 /*
-**    The maximum transfer length (should be >= 64k).
-**    MUST NOT be greater than (MAX_SCATTER-1) * NBPG.
+**    Io mapped or memory mapped.
 */
 
-#if 0
-#define MAX_SIZE  ((MAX_SCATTER-1) * (long) NBPG)
+#if defined(SCSI_NCR_IOMAPPED)
+#define NCR_IOMAPPED
 #endif
 
 /*
@@ -245,10 +248,6 @@
 
 #define NCR_SNOOP_TIMEOUT (1000000)
 
-#if defined(SCSI_NCR_IOMAPPED) || defined(__alpha__)
-#define NCR_IOMAPPED
-#endif
-
 /*==========================================================
 **
 **	Defines for Linux.
@@ -287,7 +286,7 @@
 **	virtual memory addresses of the kernel data segment into
 **	IO bus adresses.
 **	On i386 architecture, IO bus addresses match the physical
-**	addresses. But on Alpha architecture they are different.
+**	addresses. But on other architectures they can be different.
 **	In the original Bsd driver, vtophys() is called to translate
 **	data addresses to IO bus addresses. In order to minimize
 **	change, I decide to define vtophys() as virt_to_bus().
@@ -299,27 +298,42 @@
 /*
 **	Memory mapped IO
 **
-**	Linux 1.3.X allow to remap physical pages addresses greater than
-**	the highest physical memory address to kernel virtual pages.
-**	We must use vremap() to map the page and vfree() to unmap it.
-**	The memory base of ncr chips is set by the bios at a high physical
-**	address. Also we can map it, and MMIO is possible.
+**	Since linux-2.1, we must use ioremap() to map the io memory space.
+**	iounmap() to unmap it. That allows portability.
+**	Linux 1.3.X and 2.0.X allow to remap physical pages addresses greater 
+**	than the highest physical memory address to kernel virtual pages with 
+**	vremap() / vfree(). That was not portable but worked with i386 
+**	architecture.
 */
 
-static inline vm_offset_t remap_pci_mem(u_long base, u_long size)
+__initfunc(
+static vm_offset_t remap_pci_mem(u_long base, u_long size)
+)
 {
 	u_long page_base	= ((u_long) base) & PAGE_MASK;
 	u_long page_offs	= ((u_long) base) - page_base;
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
+	u_long page_remapped	= (u_long) ioremap(page_base, page_offs+size);
+#else
 	u_long page_remapped	= (u_long) vremap(page_base, page_offs+size);
+#endif
 
 	return (vm_offset_t) (page_remapped ? (page_remapped + page_offs) : 0UL);
 }
-static inline void unmap_pci_mem(vm_offset_t vaddr, u_long size)
-{
-	if (vaddr) vfree((void *) (vaddr & PAGE_MASK));
-}
 
+__initfunc(
+static void unmap_pci_mem(vm_offset_t vaddr, u_long size)
+)
+{
+	if (vaddr)
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
+		iounmap((void *) (vaddr & PAGE_MASK));
 #else
+		vfree((void *) (vaddr & PAGE_MASK));
+#endif
+}
+
+#else /* linux-1.2.13 */
 
 /*
 **	Linux 1.2.X assumes that addresses (virtual, physical, bus)
@@ -332,6 +346,10 @@
 #define vtophys(p)	((u_long) (p))
 #endif
 
+/*
+**	Insert a delay in micro-seconds.
+*/
+
 static void DELAY(long us)
 {
 	for (;us>1000;us-=1000) udelay(1000);
@@ -348,31 +366,81 @@
 **	I notice that kmalloc() returns NULL during host attach under
 **	Linux 1.2.13. But this ncr driver is reliable enough to
 **	accomodate with this joke.
-**/
+**
+**	kmalloc() only ensure 8 bytes boundary alignment.
+**	The NCR need better alignment for cache line bursting.
+**	The global header is moved betewen the NCB and CCBs and need 
+**	origin and destination addresses to have same lower four bits.
+**
+**	We use 32 boundary alignment for NCB and CCBs and offset multiple 
+**	of 32 for global header fields. That's too much but at least enough.
+*/
+
+#define ALIGN_SIZE(shift)	(1UL << shift)
+#define ALIGN_MASK(shift)	(~(ALIGN_SIZE(shift)-1))
+
+#define NCB_ALIGN_SHIFT		5
+#define CCB_ALIGN_SHIFT		5
+#define LCB_ALIGN_SHIFT		5
+#define SCR_ALIGN_SHIFT		5
+
+#define NCB_ALIGN_SIZE		ALIGN_SIZE(NCB_ALIGN_SHIFT)
+#define NCB_ALIGN_MASK		ALIGN_MASK(NCB_ALIGN_SHIFT)
+#define CCB_ALIGN_SIZE		ALIGN_SIZE(CCB_ALIGN_SHIFT)
+#define CCB_ALIGN_MASK		ALIGN_MASK(CCB_ALIGN_SHIFT)
+#define SCR_ALIGN_SIZE		ALIGN_SIZE(SCR_ALIGN_SHIFT)
+#define SCR_ALIGN_MASK		ALIGN_MASK(SCR_ALIGN_SHIFT)
+
+static void *m_alloc(int size, int a_shift)
+{
+	u_long addr;
+	void *ptr;
+	u_long a_size, a_mask;
+
+	if (a_shift < 3)
+		a_shift = 3;
+
+	a_size	= ALIGN_SIZE(a_shift);
+	a_mask	= ALIGN_MASK(a_shift);
+
+	ptr = (void *) kmalloc(size + a_size, GFP_ATOMIC);
+	if (ptr) {
+		addr	= (((u_long) ptr) + a_size) & a_mask;
+		*((void **) (addr - sizeof(void *))) = ptr;
+		ptr	= (void *) addr;
+	}
 
-static inline void *m_alloc(int size)
-{
-	void *ptr = (void *) kmalloc(size, GFP_ATOMIC);
-	if (((unsigned long) ptr) & 3)
-		panic("ncr53c8xx: kmalloc returns misaligned address %lx\n", (unsigned long) ptr);
 	return ptr;
 }
 
-static inline void m_free(void *ptr, int size)
-	{ kfree(ptr); }
+#ifdef MODULE
+static void m_free(void *ptr, int size)
+{
+	u_long addr;
+
+	if (ptr) {
+		addr	= (u_long) ptr;
+		ptr	= *((void **) (addr - sizeof(void *)));
+
+		kfree(ptr);
+	}
+}
+#endif
 
 /*
 **	Transfer direction
 **
-**	The middle scsi driver of Linux does not provide the transfer
-**	direction in the command structure.
-**	FreeBsd ncr driver require this information.
-**
-**	I spent some hours to read the scsi2 documentation to see if
-**	it was possible to deduce the direction of transfer from the opcode
-**	of the command. It seems that it's OK.
-**	guess_xfer_direction() seems to work. If it's wrong we will
-**	get a phase mismatch on some opcode.
+**	Low-level scsi drivers under Linux do not receive the expected 
+**	data transfer direction from upper scsi drivers.
+**	The driver will only check actual data direction for common 
+**	scsi opcodes. Other ones may cause problem, since they may 
+**	depend on device type or be vendor specific.
+**	I would prefer to never trust the device for data direction, 
+**	but that is not possible.
+**
+**	The original driver requires the expected direction to be known.
+**	The Linux version of the driver has been enhanced in order to 
+**	be able to transfer data in the direction choosen by the target. 
 */
 
 #define XferNone	0
@@ -385,6 +453,8 @@
 **	Head of list of NCR boards
 **
 **	Host is retrieved by its irq level.
+**	If interrupts are shared, the internal host control block 
+**	address (struct ncb) is used as device id.
 */
 
 static struct Scsi_Host		*first_host	= NULL;
@@ -419,6 +489,41 @@
 	unsigned char and_map[MAX_TARGET];
 } target_capabilities[SCSI_NCR_MAX_HOST] = { NCR53C8XX_TARGET_CAPABILITIES };
 
+/*
+**	Driver setup.
+**
+**	This structure is initialized from linux config options.
+**	It can be overridden at boot-up by the boot command line.
+*/
+struct ncr_driver_setup {
+	unsigned master_parity	: 1;
+	unsigned scsi_parity	: 1;
+	unsigned disconnection	: 1;
+	unsigned special_features : 1;
+	unsigned ultra_scsi	: 2;
+	unsigned force_sync_nego: 1;
+	unsigned reverse_probe: 1;
+	unsigned pci_fix_up: 4;
+	u_char	use_nvram;
+	u_char	verbose;
+	u_char	default_tags;
+	u_short	default_sync;
+	u_short	debug;
+	u_char	burst_max;
+	u_char	led_pin;
+	u_char	max_wide;
+	u_char	settle_delay;
+	u_char	diff_support;
+	u_char	irqm;
+};
+
+static struct ncr_driver_setup
+	driver_setup			= SCSI_NCR_DRIVER_SETUP;
+
+#ifdef	SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
+static struct ncr_driver_setup
+	driver_safe_setup __initdata	= SCSI_NCR_DRIVER_SAFE_SETUP;
+#endif
 
 /*
 **	Other Linux definitions
@@ -438,7 +543,149 @@
 
 static void ncr53c8xx_timeout(unsigned long np);
 
-#define bootverbose 1
+#define initverbose (driver_setup.verbose)
+#define bootverbose (np->verbose)
+
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+/*
+**	Symbios NvRAM data format
+*/
+#define SYMBIOS_NVRAM_SIZE 368
+#define SYMBIOS_NVRAM_ADDRESS 0x100
+
+struct Symbios_nvram {
+/* Header 6 bytes */
+	u_short start_marker;	/* 0x0000 */
+	u_short byte_count;	/* excluding header/trailer */
+	u_short checksum;
+
+/* Controller set up 20 bytes */
+	u_short	word0;		/* 0x3000 */
+	u_short	word2;		/* 0x0000 */
+	u_short	word4;		/* 0x0000 */
+	u_short	flags;
+#define SYMBIOS_SCAM_ENABLE	(1)
+#define SYMBIOS_PARITY_ENABLE	(1<<1)
+#define SYMBIOS_VERBOSE_MSGS	(1<<2)
+	u_short	flags1;
+#define SYMBIOS_SCAN_HI_LO	(1)
+	u_short	word10;		/* 0x00 */
+	u_short	word12;		/* 0x00 */
+	u_char	host_id;
+	u_char	byte15;		/* 0x04 */
+	u_short	word16;		/* 0x0410 */
+	u_short	word18;		/* 0x0000 */
+
+/* Boot order 14 bytes * 4 */
+	struct Symbios_host{
+		u_char	word0;		/* 0x0004:ok / 0x0000:nok */
+		u_short	device_id;	/* PCI device id */
+		u_short	vendor_id;	/* PCI vendor id */
+		u_char	byte6;		/* 0x00 */
+		u_char	device_fn;	/* PCI device/function number << 3*/
+		u_short	word8;
+		u_short	flags;
+#define	SYMBIOS_INIT_SCAN_AT_BOOT	(1)
+		u_short	io_port;	/* PCI io_port address */
+	} host[4];
+
+/* Targets 8 bytes * 16 */
+	struct Symbios_target {
+		u_short	flags;
+#define SYMBIOS_DISCONNECT_ENABLE	(1)
+#define SYMBIOS_SCAN_AT_BOOT_TIME	(1<<1)
+#define SYMBIOS_SCAN_LUNS		(1<<2)
+#define SYMBIOS_QUEUE_TAGS_ENABLED	(1<<3)
+		u_char	bus_width;	/* 0x08/0x10 */
+		u_char	sync_offset;
+		u_char	sync_period;	/* 4*period factor */
+		u_char	byte6;		/* 0x00 */
+		u_short	timeout;
+	} target[16];
+	u_char	spare_devices[19*8];
+	u_char	trailer[6];		/* 0xfe 0xfe 0x00 0x00 0x00 0x00 */
+};
+typedef struct Symbios_nvram	Symbios_nvram;
+typedef struct Symbios_host	Symbios_host;
+typedef struct Symbios_target	Symbios_target;
+
+/*
+**	Tekram NvRAM data format.
+*/
+#define TEKRAM_NVRAM_SIZE 64
+#define TEKRAM_NVRAM_ADDRESS 0
+
+struct Tekram_nvram {
+	struct Tekram_target {
+		u_char	flags;
+#define	TEKRAM_PARITY_CHECK		(1)
+#define TEKRAM_SYNC_NEGO		(1<<1)
+#define TEKRAM_DISCONNECT_ENABLE	(1<<2)
+#define	TEKRAM_START_CMD		(1<<3)
+#define TEKRAM_TAGGED_COMMANDS		(1<<4)
+#define TEKRAM_WIDE_NEGO		(1<<5)
+		u_char	sync_index;
+		u_short	word2;
+	} target[16];
+	u_char	host_id;
+	u_char	flags;
+#define TEKRAM_MORE_THAN_2_DRIVES	(1)
+#define TEKRAM_DRIVES_SUP_1GB		(1<<1)
+#define	TEKRAM_RESET_ON_POWER_ON	(1<<2)
+#define TEKRAM_ACTIVE_NEGATION		(1<<3)
+#define TEKRAM_IMMEDIATE_SEEK		(1<<4)
+#define	TEKRAM_SCAN_LUNS		(1<<5)
+#define	TEKRAM_REMOVABLE_FLAGS		(3<<6)	/* 0: disable; 1: boot device; 2:all */
+	u_char	boot_delay_index;
+	u_char	max_tags_index;
+	u_short	flags1;
+#define TEKRAM_F2_F6_ENABLED		(1)
+	u_short	spare[29];
+};
+typedef struct Tekram_nvram	Tekram_nvram;
+typedef struct Tekram_target	Tekram_target;
+
+static u_char Tekram_sync[12] __initdata = {25,31,37,43,50,62,75,125,12,15,18,21};
+
+#endif /* SCSI_NCR_NVRAM_SUPPORT */
+
+/*
+**	Structures used by ncr53c8xx_detect/ncr53c8xx_pci_init to 
+**	transmit device configuration to the ncr_attach() function.
+*/
+typedef struct {
+	int	bus;
+	u_char	device_fn;
+	u_int	base;
+	u_int	io_port;
+	int	irq;
+/* port and reg fields to use INB, OUTB macros */
+	u_int	port;
+	volatile struct	ncr_reg	*reg;
+} ncr_slot;
+
+typedef struct {
+	int type;
+#define	SCSI_NCR_SYMBIOS_NVRAM	(1)
+#define	SCSI_NCR_TEKRAM_NVRAM	(2)
+#ifdef	SCSI_NCR_NVRAM_SUPPORT
+	union {
+		Symbios_nvram Symbios;
+		Tekram_nvram Tekram;
+	} data;
+#endif
+} ncr_nvram;
+
+/*
+**	Structure used by ncr53c8xx_detect/ncr53c8xx_pci_init
+**	to save data on each detected board for ncr_attach().
+*/
+typedef struct {
+	ncr_slot  slot;
+	ncr_chip  chip;
+	ncr_nvram *nvram;
+	int attached;
+} ncr_device;
 
 /*==========================================================
 **
@@ -466,7 +713,7 @@
 **    Can be changed at runtime too.
 */
 
-#ifdef SCSI_NCR_DEBUG
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
 	#define DEBUG_FLAGS ncr_debug
 #else
 	#define DEBUG_FLAGS	SCSI_NCR_DEBUG_FLAGS
@@ -499,49 +746,45 @@
 **	Access to the controller chip.
 **
 **	If NCR_IOMAPPED is defined, only IO are used by the driver.
-**	Else, we begins initialisations by using MMIO.
-**		If cache test fails, we retry using IO mapped.
-**	The flag "use_mmio" in the ncb structure is set to 1 if
-**	mmio is possible.
 **
 **==========================================================
 */
 
 /*
-**	IO mapped input / ouput
+**	IO mapped only input / ouput
 */
 
-#define	IOM_INB(r)         inb (np->port + offsetof(struct ncr_reg, r))
-#define	IOM_INB_OFF(o)     inb (np->port + (o))
-#define	IOM_INW(r)         inw (np->port + offsetof(struct ncr_reg, r))
-#define	IOM_INL(r)         inl (np->port + offsetof(struct ncr_reg, r))
-#define	IOM_INL_OFF(o)     inl (np->port + (o))
-
-#define	IOM_OUTB(r, val)     outb ((val), np->port+offsetof(struct ncr_reg,r))
-#define	IOM_OUTW(r, val)     outw ((val), np->port+offsetof(struct ncr_reg,r))
-#define	IOM_OUTL(r, val)     outl ((val), np->port+offsetof(struct ncr_reg,r))
-#define	IOM_OUTL_OFF(o, val) outl ((val), np->port + (o))
+#define	IOM_INB(r)		inb (np->port + offsetof(struct ncr_reg, r))
+#define	IOM_INB_OFF(o)		inb (np->port + (o))
+#define	IOM_INW(r)		inw (np->port + offsetof(struct ncr_reg, r))
+#define	IOM_INL(r)		inl (np->port + offsetof(struct ncr_reg, r))
+#define	IOM_INL_OFF(o)		inl (np->port + (o))
+
+#define	IOM_OUTB(r, val)	outb ((val), np->port+offsetof(struct ncr_reg,r))
+#define	IOM_OUTW(r, val)	outw ((val), np->port+offsetof(struct ncr_reg,r))
+#define	IOM_OUTL(r, val)	outl ((val), np->port+offsetof(struct ncr_reg,r))
+#define	IOM_OUTL_OFF(o, val)	outl ((val), np->port + (o))
 
 /*
 **	MEMORY mapped IO input / output
 */
 
-#define MMIO_INB(r)        readb(&np->reg_remapped->r)
-#define MMIO_INB_OFF(o)    readb((char *)np->reg_remapped + (o))
-#define MMIO_INW(r)        readw(&np->reg_remapped->r)
-#define MMIO_INL(r)        readl(&np->reg_remapped->r)
-#define MMIO_INL_OFF(o)    readl((char *)np->reg_remapped + (o))
-
-#define MMIO_OUTB(r, val)     writeb((val), &np->reg_remapped->r)
-#define MMIO_OUTW(r, val)     writew((val), &np->reg_remapped->r)
-#define MMIO_OUTL(r, val)     writel((val), &np->reg_remapped->r)
-#define MMIO_OUTL_OFF(o, val) writel((val), (char *)np->reg_remapped + (o))
+#define MMIO_INB(r)		readb(&np->reg->r)
+#define MMIO_INB_OFF(o)		readb((char *)np->reg + (o))
+#define MMIO_INW(r)		readw(&np->reg->r)
+#define MMIO_INL(r)		readl(&np->reg->r)
+#define MMIO_INL_OFF(o)		readl((char *)np->reg + (o))
+
+#define MMIO_OUTB(r, val)	writeb((val), &np->reg->r)
+#define MMIO_OUTW(r, val)	writew((val), &np->reg->r)
+#define MMIO_OUTL(r, val)	writel((val), &np->reg->r)
+#define MMIO_OUTL_OFF(o, val)	writel((val), (char *)np->reg + (o))
 
 /*
-**	IO mapped only input / output
+**	IO mapped input / output
 */
 
-#ifdef NCR_IOMAPPED
+#if defined(NCR_IOMAPPED)
 
 #define INB(r)             IOM_INB(r)
 #define INB_OFF(o)         IOM_INB_OFF(o)
@@ -555,24 +798,35 @@
 #define OUTL_OFF(o, val)   IOM_OUTL_OFF(o, val)
 
 /*
-**	IO mapped or MEMORY mapped depending on flag "use_mmio"
+**	MEMORY mapped only input / output
 */
 
 #else
 
-#define	INB(r)             (np->use_mmio ? MMIO_INB(r) : IOM_INB(r))
-#define	INB_OFF(o)         (np->use_mmio ? MMIO_INB_OFF(o) : IOM_INB_OFF(o))
-#define	INW(r)             (np->use_mmio ? MMIO_INW(r) : IOM_INW(r))
-#define	INL(r)             (np->use_mmio ? MMIO_INL(r) : IOM_INL(r))
-#define	INL_OFF(o)         (np->use_mmio ? MMIO_INL_OFF(o) : IOM_INL_OFF(o))
-
-#define	OUTB(r, val)       (np->use_mmio ? MMIO_OUTB(r, val) : IOM_OUTB(r, val))
-#define	OUTW(r, val)       (np->use_mmio ? MMIO_OUTW(r, val) : IOM_OUTW(r, val))
-#define	OUTL(r, val)       (np->use_mmio ? MMIO_OUTL(r, val) : IOM_OUTL(r, val))
-#define	OUTL_OFF(o, val)   (np->use_mmio ? MMIO_OUTL_OFF(o, val) : IOM_OUTL_OFF(o, val))
+#define INB(r)             MMIO_INB(r)
+#define INB_OFF(o)         MMIO_INB_OFF(o)
+#define INW(r)             MMIO_INW(r)
+#define INL(r)             MMIO_INL(r)
+#define INL_OFF(o)         MMIO_INL_OFF(o)
+
+#define OUTB(r, val)       MMIO_OUTB(r, val)
+#define OUTW(r, val)       MMIO_OUTW(r, val)
+#define OUTL(r, val)       MMIO_OUTL(r, val)
+#define OUTL_OFF(o, val)   MMIO_OUTL_OFF(o, val)
 
 #endif
 
+/*
+**	Set bit field ON, OFF 
+*/
+
+#define OUTONB(r, m)	OUTB(r, INB(r) | (m))
+#define OUTOFFB(r, m)	OUTB(r, INB(r) & ~(m))
+#define OUTONW(r, m)	OUTW(r, INW(r) | (m))
+#define OUTOFFW(r, m)	OUTW(r, INW(r) & ~(m))
+#define OUTONL(r, m)	OUTL(r, INL(r) | (m))
+#define OUTOFFL(r, m)	OUTL(r, INL(r) & ~(m))
+
 /*==========================================================
 **
 **	Command control block states.
@@ -614,7 +868,9 @@
 #define	SIR_REJECT_SENT		(10)
 #define	SIR_IGN_RESIDUE		(11)
 #define	SIR_MISSING_SAVE	(12)
-#define	SIR_MAX			(12)
+#define	SIR_DATA_IO_IS_OUT	(13)
+#define	SIR_DATA_IO_IS_IN	(14)
+#define	SIR_MAX			(14)
 
 /*==========================================================
 **
@@ -673,7 +929,6 @@
 */
 
 #define CCB_MAGIC	(0xf2691ad2)
-#define	MAX_TAGS	(16)		/* hard limit */
 
 /*==========================================================
 **
@@ -713,7 +968,13 @@
 #define UC_SETFLAG	15
 #define UC_CLEARPROF	16
 
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+#define UC_DEBUG_ERROR_RECOVERY 17
+#endif
+
 #define	UF_TRACE	(0x01)
+#define	UF_NODISC	(0x02)
+#define	UF_NOSCAN	(0x04)
 
 /*---------------------------------------
 **
@@ -727,7 +988,6 @@
 	u_long end;
 	u_long select;
 	u_long command;
-	u_long data;
 	u_long status;
 	u_long disconnect;
 	u_long reselect;
@@ -812,6 +1072,14 @@
 	ccb_p   hold_cp;
 
 	/*
+	**	pointer to ccb used for negotiating.
+	**	Avoid to start a nego for all queued commands 
+	**	when tagged command queuing is enabled.
+	*/
+
+	ccb_p   nego_cp;
+
+	/*
 	**	statistical data
 	*/
 
@@ -821,13 +1089,18 @@
 	/*
 	**	user settable limits for sync transfer
 	**	and tagged commands.
+	**	These limits are read from the NVRAM if present.
 	*/
 
 	u_char	usrsync;
-	u_char	usrtags;
 	u_char	usrwide;
+	u_char	usrtags;
 	u_char	usrflag;
 
+	u_char	numtags;
+	u_char	maxtags;
+	u_short	num_good;
+
 	/*
 	**	negotiation of wide and synch transfer.
 	**	device quirks.
@@ -911,6 +1184,15 @@
 	u_char		usetags;
 	u_char		lasttag;
 
+	/*
+	**	Linux specific fields:
+	**	Number of active commands and current credit.
+	**	Should be managed by the generic scsi driver
+	*/
+
+	u_char		active;
+	u_char		opennings;
+
 	/*-----------------------------------------------
 	**	Flag to force M_ORDERED_TAG on next command
 	**	in order to avoid spurious timeout when
@@ -960,9 +1242,9 @@
 	**	the last transfer command.
 	*/
 
-	u_long		savep;
-	u_long		lastp;
-	u_long		goalp;
+	u_int32		savep;
+	u_int32		lastp;
+	u_int32		goalp;
 
 	/*
 	**	The virtual address of the ccb
@@ -1093,6 +1375,14 @@
 
 struct ccb {
 	/*
+	**	This field forces 32 bytes alignement for phys.header,
+	**	in order to use cache line bursting when copying it 
+	**	to the ncb.
+	*/
+
+	struct link		filler[2];
+
+	/*
 	**	during reselection the ncr jumps to this point.
 	**	If a "SIMPLE_TAG" message was received,
 	**	then SFBR is set to the tag.
@@ -1199,6 +1489,14 @@
 	*/
 
 	u_char			tag;
+
+	/*
+	**	Number of segments of the scatter list.
+	**	Used for recalculation of savep/goalp/lastp on 
+	**	SIR_DATA_IO_IS_OUT interrupt.
+	*/
+	
+	u_char			segments;
 };
 
 #define CCB_PHYS(cp,lbl)	(cp->p_ccb + offsetof(struct ccb, lbl))
@@ -1211,32 +1509,69 @@
 */
 
 struct ncb {
+	/*
+	**	The global header.
+	**	Accessible to both the host and the
+	**	script-processor.
+	**	Is 32 bytes aligned since ncb is, in order to 
+	**	allow cache line bursting when copying it from or 
+	**	to ccbs.
+	*/
+	struct head     header;
+
 	/*-----------------------------------------------
 	**	Specific Linux fields
 	**-----------------------------------------------
 	*/
 	int    unit;			/* Unit number                       */
-	int    chip;			/* Chip number                       */
+	char   chip_name[8];		/* Chip name                         */
+	char   inst_name[16];		/* Instance name                     */
 	struct timer_list timer;	/* Timer link header                 */
 	int	ncr_cache;		/* Cache test variable               */
-	int	release_stage;		/* Synchronisation stage on release  */
 	Scsi_Cmnd *waiting_list;	/* Waiting list header for commands  */
 					/* that we can't put into the squeue */
-#ifndef NCR_IOMAPPED
-	volatile struct ncr_reg*
-		reg_remapped;		/* Virtual address of the memory     */
-					/* base of the ncr chip              */
-	int	use_mmio;		/* Indicate mmio is OK               */
+	u_long	settle_time;		/* Reset in progess		     */
+	u_char	release_stage;		/* Synchronisation stage on release  */
+	u_char	verbose;		/* Boot verbosity for this controller*/
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+	u_char	debug_error_recovery;
+	u_char	stalling;
+	u_char	assert_atn;
 #endif
+
 	/*-----------------------------------------------
 	**	Added field to support differences
 	**	between ncr chips.
+	**	sv_xxx are some io register bit value at start-up and
+	**	so assumed to have been set by the sdms bios.
+	**	rv_xxx are the bit fields of io register that will keep 
+	**	the features used by the driver.
 	**-----------------------------------------------
 	*/
 	u_short	device_id;
 	u_char	revision_id;
-#define ChipDevice	((np)->device_id)
-#define ChipVersion	((np)->revision_id & 0xf0)
+
+	u_char	sv_scntl0;
+	u_char	sv_scntl3;
+	u_char	sv_dmode;
+	u_char	sv_dcntl;
+	u_char	sv_ctest3;
+	u_char	sv_ctest4;
+	u_char	sv_ctest5;
+	u_char	sv_gpcntl;
+	u_char	sv_stest2;
+	u_char	sv_stest4;
+
+	u_char	rv_scntl0;
+	u_char	rv_scntl3;
+	u_char	rv_dmode;
+	u_char	rv_dcntl;
+	u_char	rv_ctest3;
+	u_char	rv_ctest4;
+	u_char	rv_ctest5;
+	u_char	rv_stest2;
+
+	u_char	scsi_mode;
 
 	/*-----------------------------------------------
 	**	Scripts ..
@@ -1262,6 +1597,9 @@
 	vm_offset_t     vaddr;
 	vm_offset_t     paddr;
 
+	vm_offset_t     vaddr2;
+	vm_offset_t     paddr2;
+
 	/*
 	**	pointer to the chip's registers.
 	*/
@@ -1269,14 +1607,22 @@
 	struct ncr_reg* reg;
 
 	/*
-	**	A copy of the script, relocated for this ncb.
+	**	A copy of the scripts, relocated for this ncb.
+	*/
+	struct script	*script0;
+	struct scripth	*scripth0;
+
+	/*
+	**	Scripts instance virtual address.
 	*/
 	struct script	*script;
+	struct scripth	*scripth;
 
 	/*
-	**	Physical address of this instance of ncb->script
+	**	Scripts instance physical address.
 	*/
 	u_long		p_script;
+	u_long		p_scripth;
 
 	/*
 	**	The SCSI address of the host adapter.
@@ -1284,11 +1630,21 @@
 	u_char	  myaddr;
 
 	/*
+	**	Max dwords burst supported by the adapter.
+	*/
+	u_char		maxburst;	/* log base 2 of dwords burst	*/
+
+	/*
 	**	timing parameters
 	*/
-	u_char		ns_async;
-	u_char		ns_sync;
-	u_char		rv_scntl3;
+	u_char		minsync;	/* Minimum sync period factor	*/
+	u_char		maxsync;	/* Maximum sync period factor	*/
+	u_char		maxoffs;	/* Max scsi offset		*/
+	u_char		multiplier;	/* Clock multiplier (1,2,4)	*/
+	u_char		clock_divn;	/* Number of clock divisors	*/
+	u_long		clock_khz;	/* SCSI clock frequency in KHz	*/
+	u_int		features;	/* Chip features map		*/
+
 
 	/*-----------------------------------------------
 	**	Link to the generic SCSI driver
@@ -1314,7 +1670,7 @@
 	/*
 	**	Start queue.
 	*/
-	u_long		squeue [MAX_START];
+	u_int32		squeue [MAX_START];
 	u_short		squeueput;
 	u_short		actccbs;
 
@@ -1343,19 +1699,12 @@
 	u_long		disc_ref;
 
 	/*
-	**	The global header.
-	**	Accessible to both the host and the
-	**	script-processor.
-	*/
-	struct head     header;
-
-	/*
 	**	The global control block.
 	**	It's used only during the configuration phase.
 	**	A target control block will be created
 	**	after the first successful transfer.
 	*/
-	struct ccb      ccb;
+	struct ccb      *ccb;
 
 	/*
 	**	message buffers.
@@ -1365,7 +1714,7 @@
 	*/
 	u_char		msgout[8];
 	u_char		msgin [8];
-	u_long		lastmsg;
+	u_int32		lastmsg;
 
 	/*
 	**	Buffer for STATUS_IN phase.
@@ -1393,7 +1742,8 @@
 	u_short		irq;
 };
 
-#define NCB_SCRIPT_PHYS(np,lbl)	(np->p_script + offsetof (struct script, lbl))
+#define NCB_SCRIPT_PHYS(np,lbl)	 (np->p_script  + offsetof (struct script, lbl))
+#define NCB_SCRIPTH_PHYS(np,lbl) (np->p_scripth + offsetof (struct scripth, lbl))
 
 /*==========================================================
 **
@@ -1416,12 +1766,15 @@
 **----------------------------------------------------------
 */
 
+/*
+**	Script fragments which are loaded into the on-board RAM 
+**	of 825A, 875 and 895 chips.
+*/
 struct script {
 	ncrcmd	start		[  7];
 	ncrcmd	start0		[  2];
 	ncrcmd	start1		[  3];
 	ncrcmd  startpos	[  1];
-	ncrcmd  tryloop		[MAX_START*5+2];
 	ncrcmd  trysel		[  8];
 	ncrcmd	skip		[  8];
 	ncrcmd	skip2		[  3];
@@ -1439,14 +1792,6 @@
 	ncrcmd  status		[ 27];
 	ncrcmd  msg_in		[ 26];
 	ncrcmd  msg_bad		[  6];
-	ncrcmd  msg_parity	[  6];
-	ncrcmd	msg_reject	[  8];
-	ncrcmd	msg_ign_residue	[ 32];
-	ncrcmd  msg_extended	[ 18];
-	ncrcmd  msg_ext_2	[ 18];
-	ncrcmd	msg_wdtr	[ 27];
-	ncrcmd  msg_ext_3	[ 18];
-	ncrcmd	msg_sdtr	[ 27];
 	ncrcmd  complete	[ 13];
 	ncrcmd	cleanup		[ 12];
 	ncrcmd	cleanup0	[ 11];
@@ -1458,6 +1803,30 @@
 	ncrcmd  disconnect1	[ 23];
 	ncrcmd	msg_out		[  9];
 	ncrcmd	msg_out_done	[  7];
+	ncrcmd  badgetcc	[  6];
+	ncrcmd	reselect	[  8];
+	ncrcmd	reselect1	[  8];
+	ncrcmd	reselect2	[  8];
+	ncrcmd	resel_tmp	[  5];
+	ncrcmd  resel_lun	[ 18];
+	ncrcmd	resel_tag	[ 24];
+	ncrcmd  data_io		[  6];
+	ncrcmd  data_in		[MAX_SCATTER * 4 + 4];
+};
+
+/*
+**	Script fragments which stay in main memory for all chips.
+*/
+struct scripth {
+	ncrcmd  tryloop		[MAX_START*5+2];
+	ncrcmd  msg_parity	[  6];
+	ncrcmd	msg_reject	[  8];
+	ncrcmd	msg_ign_residue	[ 32];
+	ncrcmd  msg_extended	[ 18];
+	ncrcmd  msg_ext_2	[ 18];
+	ncrcmd	msg_wdtr	[ 27];
+	ncrcmd  msg_ext_3	[ 18];
+	ncrcmd	msg_sdtr	[ 27];
 	ncrcmd	msg_out_abort	[ 10];
 	ncrcmd  getcc		[  4];
 	ncrcmd  getcc1		[  5];
@@ -1467,14 +1836,7 @@
 	ncrcmd	getcc2		[ 14];
 #endif
 	ncrcmd	getcc3		[ 10];
-	ncrcmd  badgetcc	[  6];
-	ncrcmd	reselect	[ 12];
-	ncrcmd	reselect2	[  6];
-	ncrcmd	resel_tmp	[  5];
-	ncrcmd  resel_lun	[ 18];
-	ncrcmd	resel_tag	[ 24];
-	ncrcmd  data_in		[MAX_SCATTER * 4 + 7];
-	ncrcmd  data_out	[MAX_SCATTER * 4 + 7];
+	ncrcmd  data_out	[MAX_SCATTER * 4 + 4];
 	ncrcmd	aborttag	[  4];
 	ncrcmd	abort		[ 22];
 	ncrcmd	snooptest	[  9];
@@ -1493,51 +1855,59 @@
 static	void	ncr_alloc_ccb	(ncb_p np, u_long t, u_long l);
 static	void	ncr_complete	(ncb_p np, ccb_p cp);
 static	void	ncr_exception	(ncb_p np);
-static	void	ncr_free_ccb	(ncb_p np, ccb_p cp);
-static	void	ncr_getclock	(ncb_p np, u_char scntl3);
+static	void	ncr_free_ccb	(ncb_p np, ccb_p cp, u_long t, u_long l);
+static	void	ncr_getclock	(ncb_p np, int mult);
+static	void	ncr_selectclock	(ncb_p np, u_char scntl3);
 static	ccb_p	ncr_get_ccb	(ncb_p np, u_long t,u_long l);
 static	void	ncr_init	(ncb_p np, char * msg, u_long code);
-static	int	ncr_intr	(ncb_p np);
+static	int	ncr_int_sbmc	(ncb_p np);
+static	int	ncr_int_par	(ncb_p np);
 static	void	ncr_int_ma	(ncb_p np);
 static	void	ncr_int_sir	(ncb_p np);
 static  void    ncr_int_sto     (ncb_p np);
 static	u_long	ncr_lookup	(char* id);
 static	void	ncr_negotiate	(struct ncb* np, struct tcb* tp);
+static	void	ncr_opennings	(ncb_p np, lcb_p lp, Scsi_Cmnd * xp);
 
-#ifdef SCSI_NCR_PROFILE
-static	int	ncr_delta	(u_long from, u_long to);
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 static	void	ncb_profile	(ncb_p np, ccb_p cp);
 #endif
 
 static	void	ncr_script_copy_and_bind
-				(struct script * script, ncb_p np);
-static  void    ncr_script_fill (struct script * scr);
+				(ncb_p np, ncrcmd *src, ncrcmd *dst, int len);
+static  void    ncr_script_fill (struct script * scr, struct scripth * scripth);
 static	int	ncr_scatter	(ccb_p cp, Scsi_Cmnd *cmd);
-static	void	ncr_setmaxtags	(ncb_p np, tcb_p tp, u_long usrtags);
-static	void	ncr_setsync	(ncb_p np, ccb_p cp, u_char sxfer);
+static	void	ncr_setmaxtags	(ncb_p np, tcb_p tp, u_long numtags);
+static	void	ncr_getsync	(ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p);
+static	void	ncr_setsync	(ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer);
 static	void	ncr_settags     (tcb_p tp, lcb_p lp);
-static	void	ncr_setwide	(ncb_p np, ccb_p cp, u_char wide);
+static	void	ncr_setwide	(ncb_p np, ccb_p cp, u_char wide, u_char ack);
 static	int	ncr_show_msg	(u_char * msg);
 static	int	ncr_snooptest	(ncb_p np);
 static	void	ncr_timeout	(ncb_p np);
 static  void    ncr_wakeup      (ncb_p np, u_long code);
+static	void	ncr_start_reset	(ncb_p np, int settle_delay);
 
-#ifdef SCSI_NCR_USER_COMMAND
+#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
 static	void	ncr_usercmd	(ncb_p np);
 #endif
 
-static int ncr_attach (Scsi_Host_Template *tpnt, int unit, u_short device_id,
-		       u_char revision_id, int chip, u_int base, u_int io_port, 
-		       int irq, int bus, u_char device_fn);
+static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device);
 
 static void insert_into_waiting_list(ncb_p np, Scsi_Cmnd *cmd);
-static Scsi_Cmnd *remove_from_waiting_list(ncb_p np, Scsi_Cmnd *cmd);
+static Scsi_Cmnd *retrieve_from_waiting_list(int to_remove, ncb_p np, Scsi_Cmnd *cmd);
 static void process_waiting_list(ncb_p np, int sts);
 
+#define remove_from_waiting_list(np, cmd) \
+		retrieve_from_waiting_list(1, (np), (cmd))
 #define requeue_waiting_list(np) process_waiting_list((np), DID_OK)
-#define abort_waiting_list(np) process_waiting_list((np), DID_ABORT)
 #define reset_waiting_list(np) process_waiting_list((np), DID_RESET)
 
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+static	int	ncr_get_Symbios_nvram	(ncr_slot *np, Symbios_nvram *nvram);
+static	int	ncr_get_Tekram_nvram	(ncr_slot *np, Tekram_nvram *nvram);
+#endif
+
 /*==========================================================
 **
 **
@@ -1557,24 +1927,13 @@
 	+ (u_long) sizeof (struct tcb)	*  2;
 #endif
 
-#ifdef SCSI_NCR_DEBUG
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
 static int ncr_debug = SCSI_NCR_DEBUG_FLAGS;
 #endif
 
-/*==========================================================
-**
-**
-**      Global static data:	auto configure
-**
-**
-**==========================================================
-*/
-
-static char *ncr_name (ncb_p np)
+static inline char *ncr_name (ncb_p np)
 {
-	static char name[10];
-	sprintf(name, "ncr53c%d-%d", np->chip, np->unit);
-	return (name);
+	return np->inst_name;
 }
 
 
@@ -1601,10 +1960,12 @@
 #define	RELOC_LABEL	0x50000000
 #define	RELOC_REGISTER	0x60000000
 #define	RELOC_KVAR	0x70000000
+#define	RELOC_LABELH	0x80000000
 #define	RELOC_MASK	0xf0000000
 
 #define	NADDR(label)	(RELOC_SOFTC | offsetof(struct ncb, label))
 #define PADDR(label)    (RELOC_LABEL | offsetof(struct script, label))
+#define PADDRH(label)   (RELOC_LABELH | offsetof(struct scripth, label))
 #define	RADDR(label)	(RELOC_REGISTER | REG(label))
 #define	FADDR(label,ofs)(RELOC_REGISTER | ((REG(label))+(ofs)))
 #define	KVAR(which)	(RELOC_KVAR | (which))
@@ -1618,10 +1979,10 @@
  * Kernel variables referenced in the scripts.
  * THESE MUST ALL BE ALIGNED TO A 4-BYTE BOUNDARY.
  */
-static void *script_kvars[] =
+static void *script_kvars[] __initdata =
 	{ (void *)&jiffies };
 
-static	struct script script0 = {
+static	struct script script0 __initdata = {
 /*--------------------------< START >-----------------------*/ {
 	/*
 	**	Claim to be still alive ...
@@ -1661,33 +2022,7 @@
 	*/
 	SCR_JUMP,
 }/*-------------------------< STARTPOS >--------------------*/,{
-		PADDR(tryloop),
-}/*-------------------------< TRYLOOP >---------------------*/,{
-/*
-**	Load an entry of the start queue into dsa
-**	and try to start it by jumping to TRYSEL.
-**
-**	Because the size depends on the
-**	#define MAX_START parameter, it is filled
-**	in at runtime.
-**
-**-----------------------------------------------------------
-**
-**  ##===========< I=0; i<MAX_START >===========
-**  ||	SCR_COPY (4),
-**  ||		NADDR (squeue[i]),
-**  ||		RADDR (dsa),
-**  ||	SCR_CALL,
-**  ||		PADDR (trysel),
-**  ##==========================================
-**
-**	SCR_JUMP,
-**		PADDR(tryloop),
-**
-**-----------------------------------------------------------
-*/
-0
-
+		PADDRH(tryloop),
 }/*-------------------------< TRYSEL >----------------------*/,{
 	/*
 	**	Now:
@@ -1742,7 +2077,7 @@
 	**	patch the launch field.
 	**	should look like an idle process.
 	*/
-	SCR_COPY (4),
+	SCR_COPY_F (4),
 		RADDR (dsa),
 		PADDR (skip2),
 	SCR_COPY (8),
@@ -1848,7 +2183,7 @@
 	**	We patch the address part of a
 	**	COPY command with the DSA-register.
 	*/
-	SCR_COPY (4),
+	SCR_COPY_F (4),
 		RADDR (dsa),
 		PADDR (loadpos),
 	/*
@@ -1925,7 +2260,7 @@
 	SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
 		PADDR (msg_in),
 	SCR_JUMP ^ IFTRUE (DATA (M_REJECT)),
-		PADDR (msg_reject),
+		PADDRH (msg_reject),
 	/*
 	**	normal processing
 	*/
@@ -2142,7 +2477,7 @@
 	SCR_FROM_REG (socl),
 		0,
 	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
-		PADDR (msg_parity),
+		PADDRH (msg_parity),
 	SCR_FROM_REG (scratcha),
 		0,
 	/*
@@ -2157,13 +2492,13 @@
 	SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)),
 		PADDR (disconnect),
 	SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
-		PADDR (msg_extended),
+		PADDRH (msg_extended),
 	SCR_JUMP ^ IFTRUE (DATA (M_NOOP)),
 		PADDR (clrack),
 	SCR_JUMP ^ IFTRUE (DATA (M_REJECT)),
-		PADDR (msg_reject),
+		PADDRH (msg_reject),
 	SCR_JUMP ^ IFTRUE (DATA (M_IGN_RESIDUE)),
-		PADDR (msg_ign_residue),
+		PADDRH (msg_ign_residue),
 	/*
 	**	Rest of the messages left as
 	**	an exercise ...
@@ -2182,301 +2517,41 @@
 	SCR_JUMP,
 		PADDR (setmsg),
 
-}/*-------------------------< MSG_PARITY >---------------*/,{
+}/*-------------------------< COMPLETE >-----------------*/,{
 	/*
-	**	count it
+	**	Complete message.
+	**
+	**	If it's not the get condition code,
+	**	copy TEMP register to LASTP in header.
 	*/
-	SCR_REG_REG (PS_REG, SCR_ADD, 0x01),
+	SCR_FROM_REG (SS_REG),
 		0,
-	/*
-	**	send a "message parity error" message.
+/*<<<*/	SCR_JUMPR ^ IFTRUE (MASK (S_SENSE, S_SENSE)),
+		12,
+	SCR_COPY (4),
+		RADDR (temp),
+		NADDR (header.lastp),
+/*>>>*/	/*
+	**	When we terminate the cycle by clearing ACK,
+	**	the target may disconnect immediately.
+	**
+	**	We don't want to be told of an
+	**	"unexpected disconnect",
+	**	so we disable this feature.
 	*/
-	SCR_LOAD_REG (scratcha, M_PARITY),
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
 		0,
-	SCR_JUMP,
-		PADDR (setmsg),
-}/*-------------------------< MSG_REJECT >---------------*/,{
 	/*
-	**	If a negotiation was in progress,
-	**	negotiation failed.
+	**	Terminate cycle ...
 	*/
-	SCR_FROM_REG (HS_REG),
+	SCR_CLR (SCR_ACK|SCR_ATN),
 		0,
-	SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
-		SIR_NEGO_FAILED,
 	/*
-	**	else make host log this message
-	*/
-	SCR_INT ^ IFFALSE (DATA (HS_NEGOTIATE)),
-		SIR_REJECT_RECEIVED,
-	SCR_JUMP,
-		PADDR (clrack),
-
-}/*-------------------------< MSG_IGN_RESIDUE >----------*/,{
-	/*
-	**	Terminate cycle
+	**	... and wait for the disconnect.
 	*/
-	SCR_CLR (SCR_ACK),
+	SCR_WAIT_DISC,
 		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get residue size.
-	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin[1]),
-	/*
-	**	Check for message parity error.
-	*/
-	SCR_TO_REG (scratcha),
-		0,
-	SCR_FROM_REG (socl),
-		0,
-	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
-		PADDR (msg_parity),
-	SCR_FROM_REG (scratcha),
-		0,
-	/*
-	**	Size is 0 .. ignore message.
-	*/
-	SCR_JUMP ^ IFTRUE (DATA (0)),
-		PADDR (clrack),
-	/*
-	**	Size is not 1 .. have to interrupt.
-	*/
-/*<<<*/	SCR_JUMPR ^ IFFALSE (DATA (1)),
-		40,
-	/*
-	**	Check for residue byte in swide register
-	*/
-	SCR_FROM_REG (scntl2),
-		0,
-/*<<<*/	SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
-		16,
-	/*
-	**	There IS data in the swide register.
-	**	Discard it.
-	*/
-	SCR_REG_REG (scntl2, SCR_OR, WSR),
-		0,
-	SCR_JUMP,
-		PADDR (clrack),
-	/*
-	**	Load again the size to the sfbr register.
-	*/
-/*>>>*/	SCR_FROM_REG (scratcha),
-		0,
-/*>>>*/	SCR_INT,
-		SIR_IGN_RESIDUE,
-	SCR_JUMP,
-		PADDR (clrack),
-
-}/*-------------------------< MSG_EXTENDED >-------------*/,{
-	/*
-	**	Terminate cycle
-	*/
-	SCR_CLR (SCR_ACK),
-		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get length.
-	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin[1]),
-	/*
-	**	Check for message parity error.
-	*/
-	SCR_TO_REG (scratcha),
-		0,
-	SCR_FROM_REG (socl),
-		0,
-	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
-		PADDR (msg_parity),
-	SCR_FROM_REG (scratcha),
-		0,
-	/*
-	*/
-	SCR_JUMP ^ IFTRUE (DATA (3)),
-		PADDR (msg_ext_3),
-	SCR_JUMP ^ IFFALSE (DATA (2)),
-		PADDR (msg_bad),
-}/*-------------------------< MSG_EXT_2 >----------------*/,{
-	SCR_CLR (SCR_ACK),
-		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get extended message code.
-	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin[2]),
-	/*
-	**	Check for message parity error.
-	*/
-	SCR_TO_REG (scratcha),
-		0,
-	SCR_FROM_REG (socl),
-		0,
-	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
-		PADDR (msg_parity),
-	SCR_FROM_REG (scratcha),
-		0,
-	SCR_JUMP ^ IFTRUE (DATA (M_X_WIDE_REQ)),
-		PADDR (msg_wdtr),
-	/*
-	**	unknown extended message
-	*/
-	SCR_JUMP,
-		PADDR (msg_bad)
-}/*-------------------------< MSG_WDTR >-----------------*/,{
-	SCR_CLR (SCR_ACK),
-		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get data bus width
-	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin[3]),
-	SCR_FROM_REG (socl),
-		0,
-	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
-		PADDR (msg_parity),
-	/*
-	**	let the host do the real work.
-	*/
-	SCR_INT,
-		SIR_NEGO_WIDE,
-	/*
-	**	let the target fetch our answer.
-	*/
-	SCR_SET (SCR_ATN),
-		0,
-	SCR_CLR (SCR_ACK),
-		0,
-
-	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
-		SIR_NEGO_PROTO,
-	/*
-	**	Send the M_X_WIDE_REQ
-	*/
-	SCR_MOVE_ABS (4) ^ SCR_MSG_OUT,
-		NADDR (msgout),
-	SCR_CLR (SCR_ATN),
-		0,
-	SCR_COPY (1),
-		RADDR (sfbr),
-		NADDR (lastmsg),
-	SCR_JUMP,
-		PADDR (msg_out_done),
-
-}/*-------------------------< MSG_EXT_3 >----------------*/,{
-	SCR_CLR (SCR_ACK),
-		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get extended message code.
-	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin[2]),
-	/*
-	**	Check for message parity error.
-	*/
-	SCR_TO_REG (scratcha),
-		0,
-	SCR_FROM_REG (socl),
-		0,
-	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
-		PADDR (msg_parity),
-	SCR_FROM_REG (scratcha),
-		0,
-	SCR_JUMP ^ IFTRUE (DATA (M_X_SYNC_REQ)),
-		PADDR (msg_sdtr),
-	/*
-	**	unknown extended message
-	*/
-	SCR_JUMP,
-		PADDR (msg_bad)
-
-}/*-------------------------< MSG_SDTR >-----------------*/,{
-	SCR_CLR (SCR_ACK),
-		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get period and offset
-	*/
-	SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
-		NADDR (msgin[3]),
-	SCR_FROM_REG (socl),
-		0,
-	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
-		PADDR (msg_parity),
-	/*
-	**	let the host do the real work.
-	*/
-	SCR_INT,
-		SIR_NEGO_SYNC,
-	/*
-	**	let the target fetch our answer.
-	*/
-	SCR_SET (SCR_ATN),
-		0,
-	SCR_CLR (SCR_ACK),
-		0,
-
-	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
-		SIR_NEGO_PROTO,
-	/*
-	**	Send the M_X_SYNC_REQ
-	*/
-	SCR_MOVE_ABS (5) ^ SCR_MSG_OUT,
-		NADDR (msgout),
-	SCR_CLR (SCR_ATN),
-		0,
-	SCR_COPY (1),
-		RADDR (sfbr),
-		NADDR (lastmsg),
-	SCR_JUMP,
-		PADDR (msg_out_done),
-
-}/*-------------------------< COMPLETE >-----------------*/,{
-	/*
-	**	Complete message.
-	**
-	**	If it's not the get condition code,
-	**	copy TEMP register to LASTP in header.
-	*/
-	SCR_FROM_REG (SS_REG),
-		0,
-/*<<<*/	SCR_JUMPR ^ IFTRUE (MASK (S_SENSE, S_SENSE)),
-		12,
-	SCR_COPY (4),
-		RADDR (temp),
-		NADDR (header.lastp),
-/*>>>*/	/*
-	**	When we terminate the cycle by clearing ACK,
-	**	the target may disconnect immediately.
-	**
-	**	We don't want to be told of an
-	**	"unexpected disconnect",
-	**	so we disable this feature.
-	*/
-	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
-		0,
-	/*
-	**	Terminate cycle ...
-	*/
-	SCR_CLR (SCR_ACK|SCR_ATN),
-		0,
-	/*
-	**	... and wait for the disconnect.
-	*/
-	SCR_WAIT_DISC,
-		0,
-}/*-------------------------< CLEANUP >-------------------*/,{
+}/*-------------------------< CLEANUP >-------------------*/,{
 	/*
 	**      dsa:    Pointer to ccb
 	**	      or xxxxxxFF (no ccb)
@@ -2497,7 +2572,7 @@
 	/*
 	**	and copy back the header to the ccb.
 	*/
-	SCR_COPY (4),
+	SCR_COPY_F (4),
 		RADDR (dsa),
 		PADDR (cleanup0),
 	SCR_COPY (sizeof (struct head)),
@@ -2517,7 +2592,7 @@
 	SCR_FROM_REG (SS_REG),
 		0,
 	SCR_JUMP ^ IFTRUE (DATA (S_CHECK_COND)),
-		PADDR(getcc2),
+		PADDRH(getcc2),
 	/*
 	**	And make the DSA register invalid.
 	*/
@@ -2603,7 +2678,7 @@
 	**
 	**	CAUTION: only little endian architectures supported! XXX
 	*/
-	SCR_COPY (1),
+	SCR_COPY_F (1),
 		NADDR (header.savep),
 		PADDR (disconnect0),
 }/*-------------------------< DISCONNECT0 >--------------*/,{
@@ -2612,7 +2687,7 @@
 	/*
 	**	neither this
 	*/
-	SCR_COPY (1),
+	SCR_COPY_F (1),
 		NADDR (header.goalp),
 		PADDR (disconnect1),
 }/*-------------------------< DISCONNECT1 >--------------*/,{
@@ -2672,7 +2747,7 @@
 	**	If it was no ABORT message ...
 	*/
 	SCR_JUMP ^ IFTRUE (DATA (M_ABORT)),
-		PADDR (msg_out_abort),
+		PADDRH (msg_out_abort),
 	/*
 	**	... wait for the next phase
 	**	if it's a message out, send it again, ...
@@ -2693,180 +2768,24 @@
 	*/
 	SCR_JUMP,
 		PADDR (dispatch),
-}/*-------------------------< MSG_OUT_ABORT >-------------*/,{
-	/*
-	**	After ABORT message,
-	**
-	**	expect an immediate disconnect, ...
-	*/
-	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
-		0,
-	SCR_CLR (SCR_ACK|SCR_ATN),
-		0,
-	SCR_WAIT_DISC,
-		0,
-	/*
-	**	... and set the status to "ABORTED"
-	*/
-	SCR_LOAD_REG (HS_REG, HS_ABORTED),
-		0,
-	SCR_JUMP,
-		PADDR (cleanup),
-
-}/*-------------------------< GETCC >-----------------------*/,{
-	/*
-	**	The ncr doesn't have an indirect load
-	**	or store command. So we have to
-	**	copy part of the control block to a
-	**	fixed place, where we can modify it.
-	**
-	**	We patch the address part of a COPY command
-	**	with the address of the dsa register ...
-	*/
-	SCR_COPY (4),
-		RADDR (dsa),
-		PADDR (getcc1),
-	/*
-	**	... then we do the actual copy.
-	*/
-	SCR_COPY (sizeof (struct head)),
-}/*-------------------------< GETCC1 >----------------------*/,{
-		0,
-		NADDR (header),
-	/*
-	**	Initialize the status registers
-	*/
-	SCR_COPY (4),
-		NADDR (header.status),
-		RADDR (scr0),
-}/*-------------------------< GETCC2 >----------------------*/,{
-	/*
-	**	Get the condition code from a target.
-	**
-	**	DSA points to a data structure.
-	**	Set TEMP to the script location
-	**	that receives the condition code.
-	**
-	**	Because there is no script command
-	**	to load a longword into a register,
-	**	we use a CALL command.
-	*/
-/*<<<*/	SCR_CALLR,
-		24,
-	/*
-	**	Get the condition code.
-	*/
-	SCR_MOVE_TBL ^ SCR_DATA_IN,
-		offsetof (struct dsb, sense),
-	/*
-	**	No data phase may follow!
-	*/
-	SCR_CALL,
-		PADDR (checkatn),
-	SCR_JUMP,
-		PADDR (no_data),
-/*>>>*/
-
-	/*
-	**	The CALL jumps to this point.
-	**	Prepare for a RESTORE_POINTER message.
-	**	Save the TEMP register into the saved pointer.
-	*/
-	SCR_COPY (4),
-		RADDR (temp),
-		NADDR (header.savep),
-	/*
-	**	Load scratcha, because in case of a selection timeout,
-	**	the host will expect a new value for startpos in
-	**	the scratcha register.
-	*/
-	SCR_COPY (4),
-		PADDR (startpos),
-		RADDR (scratcha),
-#ifdef NCR_GETCC_WITHMSG
-	/*
-	**	If QUIRK_NOMSG is set, select without ATN.
-	**	and don't send a message.
-	*/
-	SCR_FROM_REG (QU_REG),
-		0,
-	SCR_JUMP ^ IFTRUE (MASK (QUIRK_NOMSG, QUIRK_NOMSG)),
-		PADDR(getcc3),
-	/*
-	**	Then try to connect to the target.
-	**	If we are reselected, special treatment
-	**	of the current job is required before
-	**	accepting the reselection.
-	*/
-	SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select),
-		PADDR(badgetcc),
-	/*
-	**	save target id.
-	*/
-	SCR_FROM_REG (sdid),
-		0,
-	SCR_TO_REG (ctest0),
-		0,
-	/*
-	**	Send the IDENTIFY message.
-	**	In case of short transfer, remove ATN.
-	*/
-	SCR_MOVE_TBL ^ SCR_MSG_OUT,
-		offsetof (struct dsb, smsg2),
-	SCR_CLR (SCR_ATN),
-		0,
-	/*
-	**	save the first byte of the message.
-	*/
-	SCR_COPY (1),
-		RADDR (sfbr),
-		NADDR (lastmsg),
-	SCR_JUMP,
-		PADDR (prepare2),
-
-#endif
-}/*-------------------------< GETCC3 >----------------------*/,{
-	/*
-	**	Try to connect to the target.
-	**	If we are reselected, special treatment
-	**	of the current job is required before
-	**	accepting the reselection.
-	**
-	**	Silly target won't accept a message.
-	**	Select without ATN.
-	*/
-	SCR_SEL_TBL ^ offsetof (struct dsb, select),
-		PADDR(badgetcc),
-	/*
-	**	save target id.
-	*/
-	SCR_FROM_REG (sdid),
-		0,
-	SCR_TO_REG (ctest0),
-		0,
-	/*
-	**	Force error if selection timeout
-	*/
-	SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_IN)),
-		0,
-	/*
-	**	don't negotiate.
-	*/
-	SCR_JUMP,
-		PADDR (prepare2),
-
-}/*------------------------< BADGETCC >---------------------*/,{
+}/*------------------------< BADGETCC >---------------------*/,{
 	/*
 	**	If SIGP was set, clear it and try again.
 	*/
 	SCR_FROM_REG (ctest2),
 		0,
 	SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)),
-		PADDR (getcc2),
+		PADDRH (getcc2),
 	SCR_INT,
 		SIR_SENSE_FAILED,
 }/*-------------------------< RESELECT >--------------------*/,{
 	/*
+	**	This NOP will be patched with LED OFF
+	**	SCR_REG_REG (gpreg, SCR_OR, 0x01)
+	*/
+	SCR_NO_OP,
+		0,
+	/*
 	**	make the DSA invalid.
 	*/
 	SCR_LOAD_REG (dsa, 0xff),
@@ -2881,6 +2800,13 @@
 	*/
 	SCR_WAIT_RESEL,
 		PADDR(reselect2),
+}/*-------------------------< RESELECT1 >--------------------*/,{
+	/*
+	**	This NOP will be patched with LED ON
+	**	SCR_REG_REG (gpreg, SCR_AND, 0xfe)
+	*/
+	SCR_NO_OP,
+		0,
 	/*
 	**	... zu nichts zu gebrauchen ?
 	**
@@ -2894,7 +2820,7 @@
 	**	- struct ccb
 	**	to understand what's going on.
 	*/
-	SCR_REG_SFBR (ssid, SCR_AND, 0x87),
+	SCR_REG_SFBR (ssid, SCR_AND, 0x8F),
 		0,
 	SCR_TO_REG (ctest0),
 		0,
@@ -2902,6 +2828,12 @@
 		NADDR (jump_tcb),
 }/*-------------------------< RESELECT2 >-------------------*/,{
 	/*
+	**	This NOP will be patched with LED ON
+	**	SCR_REG_REG (gpreg, SCR_AND, 0xfe)
+	*/
+	SCR_NO_OP,
+		0,
+	/*
 	**	If it's not connected :(
 	**	-> interrupted by SIGP bit.
 	**	Jump to start.
@@ -2984,80 +2916,530 @@
 /*<<<*/	SCR_JUMPR ^ IFFALSE (DATA (M_SIMPLE_TAG)),
 		48,
 	/*
-	**	It WAS a SIMPLE_TAG message.
-	**	get it and ack it!
+	**	It WAS a SIMPLE_TAG message.
+	**	get it and ack it!
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin),
+	SCR_CLR (SCR_ACK),
+		0,
+	/*
+	**	Wait for the second byte (the tag)
+	*/
+/*<<<*/	SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		24,
+	/*
+	**	Get it and ack it!
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin),
+	SCR_CLR (SCR_ACK|SCR_CARRY),
+		0,
+	SCR_RETURN,
+		0,
+	/*
+	**	No message phase or no SIMPLE_TAG message
+	**	or no second byte: return 0.
+	*/
+/*>>>*/	SCR_LOAD_SFBR (0),
+		0,
+	SCR_SET (SCR_CARRY),
+		0,
+	SCR_RETURN,
+		0,
+
+}/*-------------------------< DATA_IO >--------------------*/,{
+/*
+**	Because Linux does not provide xfer data direction 
+**	to low-level scsi drivers, we must trust the target 
+**	for actual data direction when we cannot guess it.
+**	The programmed interrupt patches savep, lastp, goalp,
+**	etc.., and restarts the scsi script at data_out/in.
+*/
+	SCR_INT ^ IFTRUE (WHEN (SCR_DATA_OUT)),
+		SIR_DATA_IO_IS_OUT,
+	SCR_INT ^ IFTRUE (WHEN (SCR_DATA_IN)),
+		SIR_DATA_IO_IS_IN,
+	SCR_JUMP,
+		PADDR (no_data),
+
+}/*-------------------------< DATA_IN >--------------------*/,{
+/*
+**	Because the size depends on the
+**	#define MAX_SCATTER parameter,
+**	it is filled in at runtime.
+**
+**  ##===========< i=0; i<MAX_SCATTER >=========
+**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
+**  ||		PADDR (checkatn),
+**  ||	SCR_MOVE_TBL ^ SCR_DATA_IN,
+**  ||		offsetof (struct dsb, data[ i]),
+**  ##==========================================
+**
+**	SCR_CALL,
+**		PADDR (checkatn),
+**	SCR_JUMP,
+**		PADDR (no_data),
+*/
+0
+}/*--------------------------------------------------------*/
+};
+
+static	struct scripth scripth0 __initdata = {
+/*-------------------------< TRYLOOP >---------------------*/{
+/*
+**	Load an entry of the start queue into dsa
+**	and try to start it by jumping to TRYSEL.
+**
+**	Because the size depends on the
+**	#define MAX_START parameter, it is filled
+**	in at runtime.
+**
+**-----------------------------------------------------------
+**
+**  ##===========< I=0; i<MAX_START >===========
+**  ||	SCR_COPY (4),
+**  ||		NADDR (squeue[i]),
+**  ||		RADDR (dsa),
+**  ||	SCR_CALL,
+**  ||		PADDR (trysel),
+**  ##==========================================
+**
+**	SCR_JUMP,
+**		PADDRH(tryloop),
+**
+**-----------------------------------------------------------
+*/
+0
+},/*-------------------------< MSG_PARITY >---------------*/{
+	/*
+	**	count it
+	*/
+	SCR_REG_REG (PS_REG, SCR_ADD, 0x01),
+		0,
+	/*
+	**	send a "message parity error" message.
+	*/
+	SCR_LOAD_REG (scratcha, M_PARITY),
+		0,
+	SCR_JUMP,
+		PADDR (setmsg),
+}/*-------------------------< MSG_REJECT >---------------*/,{
+	/*
+	**	If a negotiation was in progress,
+	**	negotiation failed.
+	*/
+	SCR_FROM_REG (HS_REG),
+		0,
+	SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
+		SIR_NEGO_FAILED,
+	/*
+	**	else make host log this message
+	*/
+	SCR_INT ^ IFFALSE (DATA (HS_NEGOTIATE)),
+		SIR_REJECT_RECEIVED,
+	SCR_JUMP,
+		PADDR (clrack),
+
+}/*-------------------------< MSG_IGN_RESIDUE >----------*/,{
+	/*
+	**	Terminate cycle
+	*/
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR (dispatch),
+	/*
+	**	get residue size.
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin[1]),
+	/*
+	**	Check for message parity error.
+	*/
+	SCR_TO_REG (scratcha),
+		0,
+	SCR_FROM_REG (socl),
+		0,
+	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+		PADDRH (msg_parity),
+	SCR_FROM_REG (scratcha),
+		0,
+	/*
+	**	Size is 0 .. ignore message.
+	*/
+	SCR_JUMP ^ IFTRUE (DATA (0)),
+		PADDR (clrack),
+	/*
+	**	Size is not 1 .. have to interrupt.
+	*/
+/*<<<*/	SCR_JUMPR ^ IFFALSE (DATA (1)),
+		40,
+	/*
+	**	Check for residue byte in swide register
+	*/
+	SCR_FROM_REG (scntl2),
+		0,
+/*<<<*/	SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
+		16,
+	/*
+	**	There IS data in the swide register.
+	**	Discard it.
+	*/
+	SCR_REG_REG (scntl2, SCR_OR, WSR),
+		0,
+	SCR_JUMP,
+		PADDR (clrack),
+	/*
+	**	Load again the size to the sfbr register.
+	*/
+/*>>>*/	SCR_FROM_REG (scratcha),
+		0,
+/*>>>*/	SCR_INT,
+		SIR_IGN_RESIDUE,
+	SCR_JUMP,
+		PADDR (clrack),
+
+}/*-------------------------< MSG_EXTENDED >-------------*/,{
+	/*
+	**	Terminate cycle
+	*/
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR (dispatch),
+	/*
+	**	get length.
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin[1]),
+	/*
+	**	Check for message parity error.
+	*/
+	SCR_TO_REG (scratcha),
+		0,
+	SCR_FROM_REG (socl),
+		0,
+	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+		PADDRH (msg_parity),
+	SCR_FROM_REG (scratcha),
+		0,
+	/*
+	*/
+	SCR_JUMP ^ IFTRUE (DATA (3)),
+		PADDRH (msg_ext_3),
+	SCR_JUMP ^ IFFALSE (DATA (2)),
+		PADDR (msg_bad),
+}/*-------------------------< MSG_EXT_2 >----------------*/,{
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR (dispatch),
+	/*
+	**	get extended message code.
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin[2]),
+	/*
+	**	Check for message parity error.
+	*/
+	SCR_TO_REG (scratcha),
+		0,
+	SCR_FROM_REG (socl),
+		0,
+	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+		PADDRH (msg_parity),
+	SCR_FROM_REG (scratcha),
+		0,
+	SCR_JUMP ^ IFTRUE (DATA (M_X_WIDE_REQ)),
+		PADDRH (msg_wdtr),
+	/*
+	**	unknown extended message
+	*/
+	SCR_JUMP,
+		PADDR (msg_bad)
+}/*-------------------------< MSG_WDTR >-----------------*/,{
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR (dispatch),
+	/*
+	**	get data bus width
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin[3]),
+	SCR_FROM_REG (socl),
+		0,
+	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+		PADDRH (msg_parity),
+	/*
+	**	let the host do the real work.
+	*/
+	SCR_INT,
+		SIR_NEGO_WIDE,
+	/*
+	**	let the target fetch our answer.
+	*/
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_CLR (SCR_ACK),
+		0,
+
+	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		SIR_NEGO_PROTO,
+	/*
+	**	Send the M_X_WIDE_REQ
+	*/
+	SCR_MOVE_ABS (4) ^ SCR_MSG_OUT,
+		NADDR (msgout),
+	SCR_CLR (SCR_ATN),
+		0,
+	SCR_COPY (1),
+		RADDR (sfbr),
+		NADDR (lastmsg),
+	SCR_JUMP,
+		PADDR (msg_out_done),
+
+}/*-------------------------< MSG_EXT_3 >----------------*/,{
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR (dispatch),
+	/*
+	**	get extended message code.
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin[2]),
+	/*
+	**	Check for message parity error.
+	*/
+	SCR_TO_REG (scratcha),
+		0,
+	SCR_FROM_REG (socl),
+		0,
+	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+		PADDRH (msg_parity),
+	SCR_FROM_REG (scratcha),
+		0,
+	SCR_JUMP ^ IFTRUE (DATA (M_X_SYNC_REQ)),
+		PADDRH (msg_sdtr),
+	/*
+	**	unknown extended message
+	*/
+	SCR_JUMP,
+		PADDR (msg_bad)
+
+}/*-------------------------< MSG_SDTR >-----------------*/,{
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR (dispatch),
+	/*
+	**	get period and offset
+	*/
+	SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
+		NADDR (msgin[3]),
+	SCR_FROM_REG (socl),
+		0,
+	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
+		PADDRH (msg_parity),
+	/*
+	**	let the host do the real work.
+	*/
+	SCR_INT,
+		SIR_NEGO_SYNC,
+	/*
+	**	let the target fetch our answer.
+	*/
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_CLR (SCR_ACK),
+		0,
+
+	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		SIR_NEGO_PROTO,
+	/*
+	**	Send the M_X_SYNC_REQ
+	*/
+	SCR_MOVE_ABS (5) ^ SCR_MSG_OUT,
+		NADDR (msgout),
+	SCR_CLR (SCR_ATN),
+		0,
+	SCR_COPY (1),
+		RADDR (sfbr),
+		NADDR (lastmsg),
+	SCR_JUMP,
+		PADDR (msg_out_done),
+
+}/*-------------------------< MSG_OUT_ABORT >-------------*/,{
+	/*
+	**	After ABORT message,
+	**
+	**	expect an immediate disconnect, ...
+	*/
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+		0,
+	SCR_CLR (SCR_ACK|SCR_ATN),
+		0,
+	SCR_WAIT_DISC,
+		0,
+	/*
+	**	... and set the status to "ABORTED"
+	*/
+	SCR_LOAD_REG (HS_REG, HS_ABORTED),
+		0,
+	SCR_JUMP,
+		PADDR (cleanup),
+
+}/*-------------------------< GETCC >-----------------------*/,{
+	/*
+	**	The ncr doesn't have an indirect load
+	**	or store command. So we have to
+	**	copy part of the control block to a
+	**	fixed place, where we can modify it.
+	**
+	**	We patch the address part of a COPY command
+	**	with the address of the dsa register ...
+	*/
+	SCR_COPY_F (4),
+		RADDR (dsa),
+		PADDRH (getcc1),
+	/*
+	**	... then we do the actual copy.
+	*/
+	SCR_COPY (sizeof (struct head)),
+}/*-------------------------< GETCC1 >----------------------*/,{
+		0,
+		NADDR (header),
+	/*
+	**	Initialize the status registers
+	*/
+	SCR_COPY (4),
+		NADDR (header.status),
+		RADDR (scr0),
+}/*-------------------------< GETCC2 >----------------------*/,{
+	/*
+	**	Get the condition code from a target.
+	**
+	**	DSA points to a data structure.
+	**	Set TEMP to the script location
+	**	that receives the condition code.
+	**
+	**	Because there is no script command
+	**	to load a longword into a register,
+	**	we use a CALL command.
+	*/
+/*<<<*/	SCR_CALLR,
+		24,
+	/*
+	**	Get the condition code.
+	*/
+	SCR_MOVE_TBL ^ SCR_DATA_IN,
+		offsetof (struct dsb, sense),
+	/*
+	**	No data phase may follow!
+	*/
+	SCR_CALL,
+		PADDR (checkatn),
+	SCR_JUMP,
+		PADDR (no_data),
+/*>>>*/
+
+	/*
+	**	The CALL jumps to this point.
+	**	Prepare for a RESTORE_POINTER message.
+	**	Save the TEMP register into the saved pointer.
+	*/
+	SCR_COPY (4),
+		RADDR (temp),
+		NADDR (header.savep),
+	/*
+	**	Load scratcha, because in case of a selection timeout,
+	**	the host will expect a new value for startpos in
+	**	the scratcha register.
+	*/
+	SCR_COPY (4),
+		PADDR (startpos),
+		RADDR (scratcha),
+#ifdef NCR_GETCC_WITHMSG
+	/*
+	**	If QUIRK_NOMSG is set, select without ATN.
+	**	and don't send a message.
+	*/
+	SCR_FROM_REG (QU_REG),
+		0,
+	SCR_JUMP ^ IFTRUE (MASK (QUIRK_NOMSG, QUIRK_NOMSG)),
+		PADDRH(getcc3),
+	/*
+	**	Then try to connect to the target.
+	**	If we are reselected, special treatment
+	**	of the current job is required before
+	**	accepting the reselection.
+	*/
+	SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select),
+		PADDR(badgetcc),
+	/*
+	**	save target id.
+	*/
+	SCR_FROM_REG (sdid),
+		0,
+	SCR_TO_REG (ctest0),
+		0,
+	/*
+	**	Send the IDENTIFY message.
+	**	In case of short transfer, remove ATN.
+	*/
+	SCR_MOVE_TBL ^ SCR_MSG_OUT,
+		offsetof (struct dsb, smsg2),
+	SCR_CLR (SCR_ATN),
+		0,
+	/*
+	**	save the first byte of the message.
 	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin),
-	SCR_CLR (SCR_ACK),
-		0,
+	SCR_COPY (1),
+		RADDR (sfbr),
+		NADDR (lastmsg),
+	SCR_JUMP,
+		PADDR (prepare2),
+
+#endif
+}/*-------------------------< GETCC3 >----------------------*/,{
 	/*
-	**	Wait for the second byte (the tag)
+	**	Try to connect to the target.
+	**	If we are reselected, special treatment
+	**	of the current job is required before
+	**	accepting the reselection.
+	**
+	**	Silly target won't accept a message.
+	**	Select without ATN.
 	*/
-/*<<<*/	SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		24,
+	SCR_SEL_TBL ^ offsetof (struct dsb, select),
+		PADDR(badgetcc),
 	/*
-	**	Get it and ack it!
+	**	save target id.
 	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin),
-	SCR_CLR (SCR_ACK|SCR_CARRY),
+	SCR_FROM_REG (sdid),
 		0,
-	SCR_RETURN,
+	SCR_TO_REG (ctest0),
 		0,
 	/*
-	**	No message phase or no SIMPLE_TAG message
-	**	or no second byte: return 0.
+	**	Force error if selection timeout
 	*/
-/*>>>*/	SCR_LOAD_SFBR (0),
-		0,
-	SCR_SET (SCR_CARRY),
-		0,
-	SCR_RETURN,
+	SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_IN)),
 		0,
+	/*
+	**	don't negotiate.
+	*/
+	SCR_JUMP,
+		PADDR (prepare2),
 
-}/*-------------------------< DATA_IN >--------------------*/,{
-/*
-**	Because the size depends on the
-**	#define MAX_SCATTER parameter,
-**	it is filled in at runtime.
-**
-**	SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
-**		PADDR (no_data),
-**	SCR_COPY (sizeof (u_long)),
-**		KVAR(SCRIPT_KVAR_JIFFIES),
-**		NADDR (header.stamp.data),
-**	SCR_MOVE_TBL ^ SCR_DATA_IN,
-**		offsetof (struct dsb, data[ 0]),
-**
-**  ##===========< i=1; i<MAX_SCATTER >=========
-**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
-**  ||		PADDR (checkatn),
-**  ||	SCR_MOVE_TBL ^ SCR_DATA_IN,
-**  ||		offsetof (struct dsb, data[ i]),
-**  ##==========================================
-**
-**	SCR_CALL,
-**		PADDR (checkatn),
-**	SCR_JUMP,
-**		PADDR (no_data),
-*/
-0
 }/*-------------------------< DATA_OUT >-------------------*/,{
 /*
 **	Because the size depends on the
 **	#define MAX_SCATTER parameter,
 **	it is filled in at runtime.
 **
-**	SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
-**		PADDR (no_data),
-**	SCR_COPY (sizeof (u_long)),
-**		KVAR(SCRIPT_KVAR_JIFFIES),
-**		NADDR (header.stamp.data),
-**	SCR_MOVE_TBL ^ SCR_DATA_OUT,
-**		offsetof (struct dsb, data[ 0]),
-**
-**  ##===========< i=1; i<MAX_SCATTER >=========
+**  ##===========< i=0; i<MAX_SCATTER >=========
 **  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
 **  ||		PADDR (dispatch),
 **  ||	SCR_MOVE_TBL ^ SCR_DATA_OUT,
@@ -3071,8 +3453,7 @@
 **
 **---------------------------------------------------------
 */
-0	/* was (u_long)&ident ? */
-
+0
 }/*-------------------------< ABORTTAG >-------------------*/,{
 	/*
 	**      Abort a bad reselection.
@@ -3146,12 +3527,14 @@
 **==========================================================
 */
 
-void ncr_script_fill (struct script * scr)
+__initfunc(
+void ncr_script_fill (struct script * scr, struct scripth * scrh)
+)
 {
 	int	i;
 	ncrcmd	*p;
 
-	p = scr->tryloop;
+	p = scrh->tryloop;
 	for (i=0; i<MAX_START; i++) {
 		*p++ =SCR_COPY (4);
 		*p++ =NADDR (squeue[i]);
@@ -3160,21 +3543,13 @@
 		*p++ =PADDR (trysel);
 	};
 	*p++ =SCR_JUMP;
-	*p++ =PADDR(tryloop);
+	*p++ =PADDRH(tryloop);
 
-	assert ((u_long)p == (u_long)&scr->tryloop + sizeof (scr->tryloop));
+	assert ((u_long)p == (u_long)&scrh->tryloop + sizeof (scrh->tryloop));
 
 	p = scr->data_in;
 
-	*p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN));
-	*p++ =PADDR (no_data);
-	*p++ =SCR_COPY (sizeof (u_long));
-	*p++ =KVAR(SCRIPT_KVAR_JIFFIES);
-	*p++ =NADDR (header.stamp.data);
-	*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
-	*p++ =offsetof (struct dsb, data[ 0]);
-
-	for (i=1; i<MAX_SCATTER; i++) {
+	for (i=0; i<MAX_SCATTER; i++) {
 		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
 		*p++ =PADDR (checkatn);
 		*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
@@ -3188,17 +3563,9 @@
 
 	assert ((u_long)p == (u_long)&scr->data_in + sizeof (scr->data_in));
 
-	p = scr->data_out;
-
-	*p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_OUT));
-	*p++ =PADDR (no_data);
-	*p++ =SCR_COPY (sizeof (u_long));
-	*p++ =KVAR(SCRIPT_KVAR_JIFFIES);
-	*p++ =NADDR (header.stamp.data);
-	*p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
-	*p++ =offsetof (struct dsb, data[ 0]);
+	p = scrh->data_out;
 
-	for (i=1; i<MAX_SCATTER; i++) {
+	for (i=0; i<MAX_SCATTER; i++) {
 		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
 		*p++ =PADDR (dispatch);
 		*p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
@@ -3210,7 +3577,7 @@
 	*p++ =SCR_JUMP;
 	*p++ =PADDR (no_data);
 
-	assert ((u_long)p == (u_long)&scr->data_out + sizeof (scr->data_out));
+	assert ((u_long)p == (u_long)&scrh->data_out + sizeof (scrh->data_out));
 }
 
 /*==========================================================
@@ -3222,19 +3589,17 @@
 **==========================================================
 */
 
-static void ncr_script_copy_and_bind (struct script *script, ncb_p np)
+__initfunc(
+static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len)
+)
 {
 	ncrcmd  opcode, new, old, tmp1, tmp2;
-	ncrcmd	*src, *dst, *start, *end;
+	ncrcmd	*start, *end;
 	int relocs;
-
-	np->p_script = vtophys(np->script);
-
-	src = script->start;
-	dst = np->script->start;
+	int opchanged = 0;
 
 	start = src;
-	end = src + (sizeof (struct script) / 4);
+	end = src + len/4;
 
 	while (src < end) {
 
@@ -3278,6 +3643,14 @@
 					ncr_name(np), (int) (src-start-1));
 				DELAY (1000000);
 			}
+			/*
+			**	If PREFETCH feature not enabled, remove 
+			**	the NO FLUSH bit if present.
+			*/
+			if ((opcode & SCR_NO_FLUSH) && !(np->features & FE_PFEN)) {
+				dst[-1] = (opcode & ~SCR_NO_FLUSH);
+				++opchanged;
+			}
 			break;
 
 		case 0x0:
@@ -3321,6 +3694,9 @@
 				case RELOC_LABEL:
 					new = (old & ~RELOC_MASK) + np->p_script;
 					break;
+				case RELOC_LABELH:
+					new = (old & ~RELOC_MASK) + np->p_scripth;
+					break;
 				case RELOC_SOFTC:
 					new = (old & ~RELOC_MASK) + vtophys(np);
 					break;
@@ -3351,6 +3727,9 @@
 			*dst++ = *src++;
 
 	};
+	if (bootverbose > 1 && opchanged)
+		printf("%s: NO FLUSH bit removed from %d script instructions\n",
+			ncr_name(np), opchanged); 
 }
 
 /*==========================================================
@@ -3362,10 +3741,6 @@
 **==========================================================
 */
 
-#define	MIN_ASYNC_PD	40
-#define	MIN_SYNC_PD	20
-
-
 /*
 **	Linux host data structure
 **
@@ -3375,25 +3750,526 @@
 */
 
 struct host_data {
-     struct ncb ncb_data;
+     struct ncb *ncb;
+
+     char ncb_align[NCB_ALIGN_SIZE-1];	/* Filler for alignment */
+     struct ncb _ncb_data;
+
+     char ccb_align[CCB_ALIGN_SIZE-1];	/* Filler for alignment */
+     struct ccb _ccb_data;
+
+     char scr_align[SCR_ALIGN_SIZE-1];	/* Filler for alignment */
      struct script script_data;
+
+     struct scripth scripth_data;
 };
 
 /*
-**	Print something which allow to retreive the controler type, unit,
+**	Print something which allow to retrieve the controler type, unit,
 **	target, lun concerned by a kernel message.
 */
 
 #define PRINT_LUN(np, target, lun) \
-printf("%s-<target %d, lun %d>: ", ncr_name(np), (int) (target), (int) (lun))
+printf(KERN_INFO "%s-<%d,%d>: ", ncr_name(np), (int) (target), (int) (lun))
 
-static inline void PRINT_ADDR(Scsi_Cmnd *cmd)
+static void PRINT_ADDR(Scsi_Cmnd *cmd)
 {
 	struct host_data *host_data = (struct host_data *) cmd->host->hostdata;
-	ncb_p np                    = &host_data->ncb_data;
+	ncb_p np                    = host_data->ncb;
 	if (np) PRINT_LUN(np, cmd->target, cmd->lun);
 }
 
+/*==========================================================
+**
+**	NCR chip clock divisor table.
+**	Divisors are multiplied by 10,000,000 in order to make 
+**	calculations more simple.
+**
+**==========================================================
+*/
+
+#define _5M 5000000
+static u_long div_10M[] =
+	{2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M};
+
+
+/*===============================================================
+**
+**	Prepare io register values used by ncr_init() according 
+**	to selected and supported features.
+**
+**	NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128 
+**	transfers. 32,64,128 are only supported by 875 and 895 chips.
+**	We use log base 2 (burst length) as internal code, with 
+**	value 0 meaning "burst disabled".
+**
+**===============================================================
+*/
+
+/*
+ *	Burst length from burst code.
+ */
+#define burst_length(bc) (!(bc))? 0 : 1 << (bc)
+
+/*
+ *	Burst code from io register bits.
+ */
+#define burst_code(dmode, ctest4, ctest5) \
+	(ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1
+
+/*
+ *	Set initial io register bits from burst code.
+ */
+static inline void ncr_init_burst(ncb_p np, u_char bc)
+{
+	np->rv_ctest4	&= ~0x80;
+	np->rv_dmode	&= ~(0x3 << 6);
+	np->rv_ctest5	&= ~0x4;
+
+	if (!bc) {
+		np->rv_ctest4	|= 0x80;
+	}
+	else {
+		--bc;
+		np->rv_dmode	|= ((bc & 0x3) << 6);
+		np->rv_ctest5	|= (bc & 0x4);
+	}
+}
+
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+
+/*
+**	Get target set-up from Symbios format NVRAM.
+*/
+
+__initfunc(
+static void
+	ncr_Symbios_setup_target(ncb_p np, int target, Symbios_nvram *nvram)
+)
+{
+	tcb_p tp = &np->target[target];
+	Symbios_target *tn = &nvram->target[target];
+
+	tp->usrsync = tn->sync_period ? (tn->sync_period + 3) / 4 : 255;
+	tp->usrwide = tn->bus_width == 0x10 ? 1 : 0;
+	tp->usrtags =
+		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? SCSI_NCR_MAX_TAGS : 0;
+
+	if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE))
+		tp->usrflag |= UF_NODISC;
+	if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME))
+		tp->usrflag |= UF_NOSCAN;
+}
+
+/*
+**	Get target set-up from Tekram format NVRAM.
+*/
+
+__initfunc(
+static void
+	ncr_Tekram_setup_target(ncb_p np, int target, Tekram_nvram *nvram)
+)
+{
+	tcb_p tp = &np->target[target];
+	struct Tekram_target *tn = &nvram->target[target];
+	int i;
+
+	if (tn->flags & TEKRAM_SYNC_NEGO) {
+		i = tn->sync_index & 0xf;
+		tp->usrsync = i < 12 ? Tekram_sync[i] : 255;
+	}
+
+	tp->usrwide = (tn->flags & TEKRAM_WIDE_NEGO) ? 1 : 0;
+
+	if (tn->flags & TEKRAM_TAGGED_COMMANDS) {
+		tp->usrtags = 2 << nvram->max_tags_index;
+		if (tp->usrtags > SCSI_NCR_MAX_TAGS)
+			tp->usrtags = SCSI_NCR_MAX_TAGS;
+	}
+
+	if (!(tn->flags & TEKRAM_DISCONNECT_ENABLE))
+		tp->usrflag = UF_NODISC;
+ 
+	/* If any device does not support parity, we will not use this option */
+	if (!(tn->flags & TEKRAM_PARITY_CHECK))
+		np->rv_scntl0  &= ~0x0a; /* SCSI parity checking disabled */
+}
+#endif /* SCSI_NCR_NVRAM_SUPPORT */
+
+__initfunc(
+static int ncr_prepare_setting(ncb_p np, ncr_nvram *nvram)
+)
+{
+	u_char	burst_max;
+	u_long	period;
+	int i;
+
+	/*
+	**	Save assumed BIOS setting
+	*/
+
+	np->sv_scntl0	= INB(nc_scntl0) & 0x0a;
+	np->sv_scntl3	= INB(nc_scntl3) & 0x07;
+	np->sv_dmode	= INB(nc_dmode)  & 0xce;
+	np->sv_dcntl	= INB(nc_dcntl)  & 0xa8;
+	np->sv_ctest3	= INB(nc_ctest3) & 0x01;
+	np->sv_ctest4	= INB(nc_ctest4) & 0x80;
+	np->sv_ctest5	= INB(nc_ctest5) & 0x24;
+	np->sv_gpcntl	= INB(nc_gpcntl);
+	np->sv_stest2	= INB(nc_stest2) & 0x20;
+	np->sv_stest4	= INB(nc_stest4);
+
+	/*
+	**	Wide ?
+	*/
+
+	np->maxwide	= (np->features & FE_WIDE)? 1 : 0;
+
+	/*
+	**	Get the frequency of the chip's clock.
+	**	Find the right value for scntl3.
+	*/
+
+	if	(np->features & FE_QUAD)
+		np->multiplier	= 4;
+	else if	(np->features & FE_DBLR)
+		np->multiplier	= 2;
+	else
+		np->multiplier	= 1;
+
+	np->clock_khz	= (np->features & FE_CLK80)? 80000 : 40000;
+	np->clock_khz	*= np->multiplier;
+
+	if (np->clock_khz != 40000)
+		ncr_getclock(np, np->multiplier);
+
+	/*
+	 * Divisor to be used for async (timer pre-scaler).
+	 */
+	i = np->clock_divn - 1;
+	while (i >= 0) {
+		--i;
+		if (10ul * SCSI_NCR_MIN_ASYNC * np->clock_khz > div_10M[i]) {
+			++i;
+			break;
+		}
+	}
+	np->rv_scntl3 = i+1;
+
+	/*
+	 * Minimum synchronous period factor supported by the chip.
+	 * Btw, 'period' is in tenths of nanoseconds.
+	 */
+
+	period = (4 * div_10M[0] + np->clock_khz - 1) / np->clock_khz;
+	if	(period <= 250)		np->minsync = 10;
+	else if	(period <= 303)		np->minsync = 11;
+	else if	(period <= 500)		np->minsync = 12;
+	else				np->minsync = (period + 40 - 1) / 40;
+
+	/*
+	 * Check against chip SCSI standard support (SCSI-2,ULTRA,ULTRA2).
+	 */
+
+	if	(np->minsync < 25 && !(np->features & (FE_ULTRA|FE_ULTRA2)))
+		np->minsync = 25;
+	else if	(np->minsync < 12 && !(np->features & FE_ULTRA2))
+		np->minsync = 12;
+
+	/*
+	 * Maximum synchronous period factor supported by the chip.
+	 */
+
+	period = (11 * div_10M[np->clock_divn - 1]) / (4 * np->clock_khz);
+	np->maxsync = period > 2540 ? 254 : period / 10;
+
+	/*
+	**	Get on-board RAM bus address when supported
+	*/
+	if (np->features & FE_RAM) {
+		OUTONB(nc_ctest2, 0x8);
+		np->paddr2 = INL(nc_scr0);
+		OUTOFFB(nc_ctest2, 0x8);
+	}
+
+	/*
+	**	Prepare initial value of other IO registers
+	*/
+#if defined SCSI_NCR_TRUST_BIOS_SETTING
+	np->rv_scntl0	= np->sv_scntl0;
+	np->rv_dmode	= np->sv_dmode;
+	np->rv_dcntl	= np->sv_dcntl;
+	np->rv_ctest3	= np->sv_ctest3;
+	np->rv_ctest4	= np->sv_ctest4;
+	np->rv_ctest5	= np->sv_ctest5;
+	burst_max	= burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
+#else
+
+	/*
+	**	Select burst length (dwords)
+	*/
+	burst_max	= driver_setup.burst_max;
+	if (burst_max == 255)
+		burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5);
+	if (burst_max > 7)
+		burst_max = 7;
+	if (burst_max > np->maxburst)
+		burst_max = np->maxburst;
+
+	/*
+	**	Select all supported special features
+	*/
+	if (np->features & FE_ERL)
+		np->rv_dmode	|= ERL;		/* Enable Read Line */
+	if (np->features & FE_BOF)
+		np->rv_dmode	|= BOF;		/* Burst Opcode Fetch */
+	if (np->features & FE_ERMP)
+		np->rv_dmode	|= ERMP;	/* Enable Read Multiple */
+	if (np->features & FE_PFEN)
+		np->rv_dcntl	|= PFEN;	/* Prefetch Enable */
+	if (np->features & FE_CLSE)
+		np->rv_dcntl	|= CLSE;	/* Cache Line Size Enable */
+	if (np->features & FE_WRIE)
+		np->rv_ctest3	|= WRIE;	/* Write and Invalidate */
+	if (np->features & FE_DFS)
+		np->rv_ctest5	|= DFS;		/* Dma Fifo Size */
+
+	/*
+	**	Select some other
+	*/
+	if (driver_setup.master_parity)
+		np->rv_ctest4	|= MPEE;	/* Master parity checking */
+	if (driver_setup.scsi_parity)
+		np->rv_scntl0	|= 0x0a;	/*  full arb., ena parity, par->ATN  */
+
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+	/*
+	**	Get parity checking, host ID and verbose mode from NVRAM
+	**/
+	if (nvram) {
+		switch(nvram->type) {
+		case SCSI_NCR_TEKRAM_NVRAM:
+			np->myaddr = nvram->data.Tekram.host_id & 0x0f;
+			break;
+		case SCSI_NCR_SYMBIOS_NVRAM:
+			if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE))
+				np->rv_scntl0  &= ~0x0a;
+			np->myaddr = nvram->data.Symbios.host_id & 0x0f;
+			if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS)
+				np->verbose += 1;
+			break;
+		}
+	}
+#endif
+	/*
+	**  Get SCSI addr of host adapter (set by bios?).
+	*/
+	if (!np->myaddr) np->myaddr = INB(nc_scid) & 0x07;
+	if (!np->myaddr) np->myaddr = SCSI_NCR_MYADDR;
+
+
+#endif /* SCSI_NCR_TRUST_BIOS_SETTING */
+
+	/*
+	 *	Prepare initial io register bits for burst length
+	 */
+	ncr_init_burst(np, burst_max);
+
+	/*
+	**	Set differential mode and LED support.
+	**	Ignore these features for boards known to use a 
+	**	specific GPIO wiring (Tekram only for now).
+	**	Probe initial setting of GPREG and GPCNTL for 
+	**	other ones.
+	*/
+	if (!nvram || nvram->type != SCSI_NCR_TEKRAM_NVRAM) {
+		switch(driver_setup.diff_support) {
+		case 3:
+			if (INB(nc_gpreg) & 0x08)
+			break;
+		case 2:
+			np->rv_stest2	|= 0x20;
+			break;
+		case 1:
+			np->rv_stest2	|= (np->sv_stest2 & 0x20);
+			break;
+		default:
+			break;
+		}
+	}
+	if ((driver_setup.led_pin ||
+	     (nvram && nvram->type == SCSI_NCR_SYMBIOS_NVRAM)) &&
+	    !(np->sv_gpcntl & 0x01))
+		np->features |= FE_LED0;
+
+	/*
+	**	Set irq mode.
+	*/
+	switch(driver_setup.irqm) {
+	case 2:
+		np->rv_dcntl	|= IRQM;
+		break;
+	case 1:
+		np->rv_dcntl	|= (np->sv_dcntl & IRQM);
+		break;
+	default:
+		break;
+	}
+
+	/*
+	**	Configure targets according to driver setup.
+	**	If NVRAM present get targets setup from NVRAM.
+	**	Allow to override sync, wide and NOSCAN from 
+	**	boot command line.
+	*/
+	for (i = 0 ; i < MAX_TARGET ; i++) {
+		tcb_p tp = &np->target[i];
+
+		tp->usrsync = 255;
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+		if (nvram) {
+			switch(nvram->type) {
+			case SCSI_NCR_TEKRAM_NVRAM:
+				ncr_Tekram_setup_target(np, i, &nvram->data.Tekram);
+				break;
+			case SCSI_NCR_SYMBIOS_NVRAM:
+				ncr_Symbios_setup_target(np, i, &nvram->data.Symbios);
+				break;
+			}
+			if (driver_setup.use_nvram & 0x2)
+				tp->usrsync = driver_setup.default_sync;
+			if (driver_setup.use_nvram & 0x4)
+				tp->usrwide = driver_setup.max_wide;
+			if (driver_setup.use_nvram & 0x8)
+				tp->usrflag &= ~UF_NOSCAN;
+		}
+		else {
+#else
+		if (1) {
+#endif
+			tp->usrsync = driver_setup.default_sync;
+			tp->usrwide = driver_setup.max_wide;
+			tp->usrtags = driver_setup.default_tags;
+			if (!driver_setup.disconnection)
+				np->target[i].usrflag = UF_NODISC;
+		}
+	}
+
+	/*
+	**	Announce all that stuff to user.
+	*/
+
+	i = nvram ? nvram->type : 0;
+	printf(KERN_INFO "%s: %sID %d, Fast-%d%s%s\n", ncr_name(np),
+		i  == SCSI_NCR_SYMBIOS_NVRAM ? "Symbios format NVRAM, " :
+		(i == SCSI_NCR_TEKRAM_NVRAM  ? "Tekram format NVRAM, " : ""),
+		np->myaddr,
+		np->minsync < 12 ? 40 : (np->minsync < 25 ? 20 : 10),
+		(np->rv_scntl0 & 0xa)	? ", Parity Checking"	: ", NO Parity",
+		(np->rv_stest2 & 0x20)	? ", Differential"	: "");
+
+	if (bootverbose > 1) {
+		printf ("%s: initial SCNTL3/DMODE/DCNTL/CTEST3/4/5 = "
+			"(hex) %02x/%02x/%02x/%02x/%02x/%02x\n",
+			ncr_name(np), np->sv_scntl3, np->sv_dmode, np->sv_dcntl,
+			np->sv_ctest3, np->sv_ctest4, np->sv_ctest5);
+
+		printf ("%s: final   SCNTL3/DMODE/DCNTL/CTEST3/4/5 = "
+			"(hex) %02x/%02x/%02x/%02x/%02x/%02x\n",
+			ncr_name(np), np->rv_scntl3, np->rv_dmode, np->rv_dcntl,
+			np->rv_ctest3, np->rv_ctest4, np->rv_ctest5);
+	}
+
+	if (bootverbose && np->paddr2)
+		printf (KERN_INFO "%s: on-board RAM at 0x%lx\n",
+			ncr_name(np), np->paddr2);
+
+	return 0;
+}
+
+
+#ifdef SCSI_NCR_DEBUG_NVRAM
+
+__initfunc(
+void ncr_display_Symbios_nvram(ncb_p np, Symbios_nvram *nvram)
+)
+{
+	int i;
+
+	/* display Symbios nvram host data */
+	printf("%s: HOST ID=%d%s%s%s%s\n",
+		ncr_name(np), nvram->host_id & 0x0f,
+		(nvram->flags  & SYMBIOS_SCAM_ENABLE)	? " SCAM"	:"",
+		(nvram->flags  & SYMBIOS_PARITY_ENABLE)	? " PARITY"	:"",
+		(nvram->flags  & SYMBIOS_VERBOSE_MSGS)	? " VERSBOSE"	:"", 
+		(nvram->flags1 & SYMBIOS_SCAN_HI_LO)	? " HI_LO"	:"");
+
+	/* display Symbios nvram drive data */
+	for (i = 0 ; i < 15 ; i++) {
+		struct Symbios_target *tn = &nvram->target[i];
+		printf("%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n",
+		ncr_name(np), i,
+		(tn->flags & SYMBIOS_DISCONNECT_ENABLE)	? " DISC"	: "",
+		(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME)	? " SCAN_BOOT"	: "",
+		(tn->flags & SYMBIOS_SCAN_LUNS)		? " SCAN_LUNS"	: "",
+		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ"	: "",
+		tn->bus_width,
+		tn->sync_period / 4,
+		tn->timeout);
+	}
+}
+
+static u_char Tekram_boot_delay[7] __initdata = {3, 5, 10, 20, 30, 60, 120};
+
+__initfunc(
+void ncr_display_Tekram_nvram(ncb_p np, Tekram_nvram *nvram)
+)
+{
+	int i, tags, boot_delay;
+	char *rem;
+
+	/* display Tekram nvram host data */
+	tags = 2 << nvram->max_tags_index;
+	boot_delay = 0;
+	if (nvram->boot_delay_index < 6)
+		boot_delay = Tekram_boot_delay[nvram->boot_delay_index];
+	switch((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) {
+	default:
+	case 0:	rem = "";			break;
+	case 1: rem = " REMOVABLE=boot device";	break;
+	case 2: rem = " REMOVABLE=all";		break;
+	}
+
+	printf("%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n",
+		ncr_name(np), nvram->host_id & 0x0f,
+		(nvram->flags1 & SYMBIOS_SCAM_ENABLE)	? " SCAM"	:"",
+		(nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES"	:"",
+		(nvram->flags & TEKRAM_DRIVES_SUP_1GB)	? " >1GB"	:"",
+		(nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET"	:"",
+		(nvram->flags & TEKRAM_ACTIVE_NEGATION)	? " ACT_NEG"	:"",
+		(nvram->flags & TEKRAM_IMMEDIATE_SEEK)	? " IMM_SEEK"	:"",
+		(nvram->flags & TEKRAM_SCAN_LUNS)	? " SCAN_LUNS"	:"",
+		(nvram->flags1 & TEKRAM_F2_F6_ENABLED)	? " F2_F6"	:"",
+		rem, boot_delay, tags);
+
+	/* display Tekram nvram drive data */
+	for (i = 0; i <= 15; i++) {
+		int sync, j;
+		struct Tekram_target *tn = &nvram->target[i];
+		j = tn->sync_index & 0xf;
+		sync = j < 12 ? Tekram_sync[j] : 255;
+		printf("%s-%d:%s%s%s%s%s%s PERIOD=%d\n",
+		ncr_name(np), i,
+		(tn->flags & TEKRAM_PARITY_CHECK)	? " PARITY"	: "",
+		(tn->flags & TEKRAM_SYNC_NEGO)		? " SYNC"	: "",
+		(tn->flags & TEKRAM_DISCONNECT_ENABLE)	? " DISC"	: "",
+		(tn->flags & TEKRAM_START_CMD)		? " START"	: "",
+		(tn->flags & TEKRAM_TAGGED_COMMANDS)	? " TCQ"	: "",
+		(tn->flags & TEKRAM_WIDE_NEGO)		? " WIDE"	: "",
+		sync);
+	}
+}
+#endif /* SCSI_NCR_DEBUG_NVRAM */
 
 /*
 **	Host attach and initialisations.
@@ -3401,24 +4277,23 @@
 **	Allocate host data and ncb structure.
 **	Request IO region and remap MMIO region.
 **	Do chip initialization.
-**	Try with mmio.
-**	If mmio not possible (misconfigured cache),
-**	retry with io mapped.
 **	If all is OK, install interrupt handling and
 **	start the timer daemon.
 */
 
-static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ushort device_id,
-		       u_char revision_id, int chip, u_int base, u_int io_port, 
-		       int irq, int bus, u_char device_fn)
-
+__initfunc(
+static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
+)
 {
         struct host_data *host_data;
 	ncb_p np;
         struct Scsi_Host *instance = 0;
 	u_long flags = 0;
+	ncr_nvram *nvram = device->nvram;
 
-printf("ncr_attach: unit=%d chip=%d base=%x, io_port=%x, irq=%d\n", unit, chip, base, io_port, irq);
+printf(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%x, io_port=0x%x, irq=%d\n",
+	device->chip.name, unit, device->chip.revision_id, device->slot.base,
+	device->slot.io_port, device->slot.irq);
 
 	/*
 	**	Allocate host_data structure
@@ -3429,16 +4304,36 @@
 	/*
 	**	Initialize structure.
 	*/
-	instance->irq = irq;
 	host_data = (struct host_data *) instance->hostdata;
 
-	np        = &host_data->ncb_data;
+	/*
+	**	Align np and first ccb to 32 boundary for cache line 
+	**	bursting when copying the global header.
+	*/
+	np        = (ncb_p) (((u_long) &host_data->_ncb_data) & NCB_ALIGN_MASK);
+	host_data->ncb = np;
 	bzero (np, sizeof (*np));
-	np->unit = unit;
-	np->chip = chip;
-	np->device_id	= device_id;
-	np->revision_id	= revision_id;
-	np->script = &host_data->script_data;
+
+	np->ccb   = (ccb_p) (((u_long) &host_data->_ccb_data) & CCB_ALIGN_MASK);
+	bzero (np->ccb, sizeof (*np->ccb));
+
+	/*
+	**	Store input informations in the host data structure.
+	*/
+	strncpy(np->chip_name, device->chip.name, sizeof(np->chip_name) - 1);
+	np->unit	= unit;
+	np->verbose	= driver_setup.verbose;
+	sprintf(np->inst_name, "ncr53c%s-%d", np->chip_name, np->unit);
+	np->device_id	= device->chip.device_id;
+	np->revision_id	= device->chip.revision_id;
+	np->features	= device->chip.features;
+	np->clock_divn	= device->chip.nr_divisor;
+	np->maxoffs	= device->chip.offset_max;
+	np->maxburst	= device->chip.burst_max;
+
+	np->script0  =
+	(struct script *) (((u_long) &host_data->script_data) & SCR_ALIGN_MASK);
+	np->scripth0 = &host_data->scripth_data;
 
 	/*
 	**    Initialize timer structure
@@ -3453,38 +4348,74 @@
 	**	virtual and physical memory.
 	*/
 
-	np->paddr = base;
-	np->vaddr = base;
+	np->paddr = device->slot.base;
 
 #ifndef NCR_IOMAPPED
-	np->reg_remapped = (struct ncr_reg *) remap_pci_mem((u_long) base, (u_long) 128);
-	if (!np->reg_remapped) {
+	np->vaddr = remap_pci_mem((u_long) np->paddr, (u_long) 128);
+	if (!np->vaddr) {
 		printf("%s: can't map memory mapped IO region\n", ncr_name(np));
-		np->use_mmio = 0;
+		goto attach_error;
 	}
-	printf("%s: using memory mapped IO at virtual address 0x%lx\n", ncr_name(np), (u_long) np->reg_remapped);
-		np->use_mmio = 1;
-#endif
+	else
+		if (bootverbose > 1)
+			printf("%s: using memory mapped IO at virtual address 0x%lx\n", ncr_name(np), (u_long) np->vaddr);
+
+	/*
+	**	Make the controller's registers available.
+	**	Now the INB INW INL OUTB OUTW OUTL macros
+	**	can be used safely.
+	*/
+
+	np->reg = (struct ncr_reg*) np->vaddr;
+
+#endif /* !defined NCR_IOMAPPED */
+
 	/*
 	**	Try to map the controller chip into iospace.
 	*/
 
-	request_region(io_port, 128, "ncr53c8xx");
-	np->port = io_port;
+	request_region(device->slot.io_port, 128, "ncr53c8xx");
+	np->port = device->slot.io_port;
+
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+	if (nvram) {
+		switch(nvram->type) {
+		case SCSI_NCR_SYMBIOS_NVRAM:
+#ifdef SCSI_NCR_DEBUG_NVRAM
+			ncr_display_Symbios_nvram(np, &nvram->data.Symbios);
+#endif
+			break;
+		case SCSI_NCR_TEKRAM_NVRAM:
+#ifdef SCSI_NCR_DEBUG_NVRAM
+			ncr_display_Tekram_nvram(np, &nvram->data.Tekram);
+#endif
+			break;
+		default:
+			nvram = 0;
+#ifdef SCSI_NCR_DEBUG_NVRAM
+			printf("%s: NVRAM: None or invalid data.\n", ncr_name(np));
+#endif
+		}
+	}
+#endif
 
 	/*
 	**	Do chip dependent initialization.
 	*/
+	(void)ncr_prepare_setting(np, nvram);
 
-	switch (device_id) {
-	case PCI_DEVICE_ID_NCR_53C825:
-	case PCI_DEVICE_ID_NCR_53C875:
-		np->maxwide = 1;
-		break;
-	default:
-		np->maxwide = 0;
-		break;
+#ifndef NCR_IOMAPPED
+	if (np->paddr2 && sizeof(struct script) <= 4096) {
+		np->vaddr2 = remap_pci_mem((u_long) np->paddr2, (u_long) 4096);
+		if (!np->vaddr2) {
+			printf("%s: can't map memory mapped IO region\n", ncr_name(np));
+			goto attach_error;
+		}
+		else
+			if (bootverbose > 1)
+				printf("%s: on-board ram mapped at virtual address 0x%lx\n", ncr_name(np), (u_long) np->vaddr2);
 	}
+#endif /* !defined NCR_IOMAPPED */
 
 	/*
 	**	Fill Linux host instance structure
@@ -3495,9 +4426,10 @@
 	instance->max_lun	= SCSI_NCR_MAX_LUN;
 #endif
 #ifndef NCR_IOMAPPED
-	instance->base		= (char *) np->reg_remapped;
+	instance->base		= (char *) np->reg;
 #endif
-	instance->io_port	= io_port;
+	instance->irq		= device->slot.irq;
+	instance->io_port	= device->slot.io_port;
 	instance->n_io_port	= 128;
 	instance->dma_channel	= 0;
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0)
@@ -3507,58 +4439,39 @@
 	/*
 	**	Patch script to physical addresses
 	*/
-	ncr_script_fill (&script0);
-	ncr_script_copy_and_bind (&script0, np);
-	np->ccb.p_ccb		= vtophys (&np->ccb);
+	ncr_script_fill (&script0, &scripth0);
 
-	/*
-	**	init data structure
-	*/
-
-	np->jump_tcb.l_cmd	= SCR_JUMP;
-	np->jump_tcb.l_paddr	= NCB_SCRIPT_PHYS (np, abort);
-
-	/*
-	**	Make the controller's registers available.
-	**	Now the INB INW INL OUTB OUTW OUTL macros
-	**	can be used safely.
-	*/
+	np->scripth	= np->scripth0;
+	np->p_scripth	= vtophys(np->scripth);
 
-	np->reg = (struct ncr_reg*) np->vaddr;
+	np->script	= (np->vaddr2) ? (struct script *) np->vaddr2 : np->script0;
+	np->p_script	= (np->vaddr2) ? np->paddr2 : vtophys(np->script0);
 
-#ifndef NCR_IOMAPPED
-retry_chip_init:
-#endif
+	ncr_script_copy_and_bind (np, (ncrcmd *) &script0, (ncrcmd *) np->script0, sizeof(struct script));
+	ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth));
+	np->ccb->p_ccb		= vtophys (np->ccb);
 
 	/*
-	**  Get SCSI addr of host adapter (set by bios?).
+	**    Patch the script for LED support.
 	*/
 
-	np->myaddr = INB(nc_scid) & 0x07;
-	if (!np->myaddr) np->myaddr = SCSI_NCR_MYADDR;
+	if (np->features & FE_LED0) {
+		np->script0->reselect[0]  = SCR_REG_REG(gpreg, SCR_OR,  0x01);
+		np->script0->reselect1[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
+		np->script0->reselect2[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe);
+	}
 
 	/*
-	**	Get the value of the chip's clock.
-	**	Find the right value for scntl3.
+	**	init data structure
 	*/
 
-	ncr_getclock (np, INB(nc_scntl3));
+	np->jump_tcb.l_cmd	= SCR_JUMP;
+	np->jump_tcb.l_paddr	= NCB_SCRIPTH_PHYS (np, abort);
 
 	/*
 	**	Reset chip.
 	*/
 
-	OUTW (nc_sien , 0);	/* Disable scsi interrupts */
-	OUTB (nc_dien , 0);	/* Disable dma interrupts */
-
-	OUTB (nc_istat,  SRST);
-	DELAY (1000);
-	OUTB (nc_istat,  0   );
-
-	/*
-	**	Reset chip, once again.
-	*/
-
 	OUTB (nc_istat,  SRST);
 	DELAY (1000);
 	OUTB (nc_istat,  0   );
@@ -3568,14 +4481,6 @@
 	*/
 
 	if (ncr_snooptest (np)) {
-#ifndef NCR_IOMAPPED
-		if (np->use_mmio) {
-printf("%s: cache misconfigured, retrying with IO mapped at 0x%lx\n",
-	ncr_name(np), (u_long) np->port);
-			np->use_mmio = 0;
-			goto retry_chip_init;
-		}
-#endif
 		printf ("CACHE INCORRECTLY CONFIGURED.\n");
 		goto attach_error;
 	};
@@ -3584,55 +4489,50 @@
 	**	Install the interrupt handler.
 	*/
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
-#   ifdef SCSI_NCR_SHARE_IRQ
-	printf("%s: requesting shared irq %d (dev_id=0x%lx)\n",
-	        ncr_name(np), irq, (u_long) np);
-	if (request_irq(irq, ncr53c8xx_intr, SA_INTERRUPT|SA_SHIRQ, "53c8xx", np)) {
-#   else
-	if (request_irq(irq, ncr53c8xx_intr, SA_INTERRUPT, "53c8xx", NULL)) {
-#   endif
+#ifdef SCSI_NCR_SHARE_IRQ
+	if (bootverbose > 1)
+		printf("%s: requesting shared irq %d (dev_id=0x%lx)\n",
+		        ncr_name(np), device->slot.irq, (u_long) np);
+	if (request_irq(device->slot.irq, ncr53c8xx_intr,
+			SA_INTERRUPT|SA_SHIRQ, "ncr53c8xx", np)) {
+#else
+	if (request_irq(device->slot.irq, ncr53c8xx_intr,
+			SA_INTERRUPT, "ncr53c8xx", NULL)) {
+#endif
 #else
-	if (request_irq(irq, ncr53c8xx_intr, SA_INTERRUPT, "53c8xx")) {
+	if (request_irq(device->slot.irq, ncr53c8xx_intr,
+			SA_INTERRUPT, "ncr53c8xx")) {
 #endif
-		printf("%s: request irq %d failure\n", ncr_name(np), irq);
+		printf("%s: request irq %d failure\n", ncr_name(np), device->slot.irq);
 		goto attach_error;
 	}
-	np->irq = irq;
+	np->irq = device->slot.irq;
 
 	/*
 	**	After SCSI devices have been opened, we cannot
 	**	reset the bus safely, so we do it here.
 	**	Interrupt handler does the real work.
-	*/
-
-	OUTB (nc_scntl1, CRST);
-	DELAY (1000);
-
-	/*
 	**	Process the reset exception,
 	**	if interrupts are not enabled yet.
 	**	Then enable disconnects.
 	*/
 	save_flags(flags); cli();
+	ncr_start_reset(np, driver_setup.settle_delay);
 	ncr_exception (np);
 	restore_flags(flags);
 
-#ifndef SCSI_NCR_NO_DISCONNECT
 	np->disc = 1;
-#endif
 
 	/*
 	**	The middle-level SCSI driver does not
 	**	wait devices to settle.
+	**	Wait synchronously if more than 2 seconds.
 	*/
-#ifdef SCSI_NCR_SETTLE_TIME
-#if    SCSI_NCR_SETTLE_TIME > 2
-	printf("%s: waiting for scsi devices to settle...\n", ncr_name(np));
-#endif
-#if    SCSI_NCR_SETTLE_TIME > 0
-	DELAY(SCSI_NCR_SETTLE_TIME*1000000);
-#endif
-#endif
+	if (driver_setup.settle_delay > 2) {
+		printf("%s: waiting %d seconds for scsi devices to settle...\n",
+			ncr_name(np), driver_setup.settle_delay);
+		DELAY(1000000UL * driver_setup.settle_delay);
+	}
 
 	/*
 	**	Now let the generic SCSI driver
@@ -3642,8 +4542,8 @@
 	/*
 	**	start the timeout daemon
 	*/
-	ncr_timeout (np);
 	np->lasttime=0;
+	ncr_timeout (np);
 
 	/*
 	**  use SIMPLE TAG messages by default
@@ -3664,14 +4564,25 @@
 
 attach_error:
 	if (!instance) return -1;
+	printf("%s: detaching...\n", ncr_name(np));
 #ifndef NCR_IOMAPPED
-	if (np->reg_remapped) {
-		printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->reg_remapped, 128);
-		unmap_pci_mem((vm_offset_t) np->reg_remapped, (u_long) 128);
+	if (np->vaddr) {
+#ifdef DEBUG_NCR53C8XX
+		printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
+#endif
+		unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
+	}
+	if (np->vaddr2) {
+#ifdef DEBUG_NCR53C8XX
+		printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096);
+#endif
+		unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096);
 	}
 #endif
 	if (np->port) {
+#ifdef DEBUG_NCR53C8XX
 		printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
+#endif
 		release_region(np->port, 128);
 	}
 	scsi_unregister(instance);
@@ -3682,47 +4593,6 @@
 /*==========================================================
 **
 **
-**	Process pending device interrupts.
-**
-**
-**==========================================================
-*/
-int ncr_intr(np)
-	ncb_p np;
-{
-	int n = 0;
-	u_long flags;
-
-	save_flags(flags); cli();
-
-	if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
-
-#ifdef SCSI_NCR_PARANOIA
-	if (INB(nc_istat) & (INTF|SIP|DIP)) {
-		/*
-		**	Repeat until no outstanding ints
-		*/
-		do {
-#endif
-			ncr_exception (np);
-#ifdef SCSI_NCR_PARANOIA
-		} while (INB(nc_istat) & (INTF|SIP|DIP));
-
-		n=1;
-		np->ticks = 5 * HZ;
-	};
-#endif
-
-	if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
-
-	restore_flags(flags);
-
-	return (n);
-}
-
-/*==========================================================
-**
-**
 **	Start execution of a SCSI command.
 **	This is called from the generic SCSI driver.
 **
@@ -3734,7 +4604,7 @@
         struct Scsi_Host   *host      = cmd->host;
 /*	Scsi_Device        *device    = cmd->device; */
 	struct host_data   *host_data = (struct host_data *) host->hostdata;
-	ncb_p np                      = &host_data->ncb_data;
+	ncb_p np                      = host_data->ncb;
 	tcb_p tp                      = &np->target[cmd->target];
 
 	ccb_p cp;
@@ -3742,7 +4612,7 @@
 
 	int	segments;
 	u_char	qidx, nego, idmsg, *msgptr;
-	u_long  msglen, msglen2;
+	u_int  msglen, msglen2;
 	u_long	flags;
 	int	xfer_direction;
 
@@ -3753,22 +4623,6 @@
 
 	/*---------------------------------------------
 	**
-	**   Reset SCSI bus
-	**
-	**	Interrupt handler does the real work.
-	**
-	**---------------------------------------------
-	*/
-#if 0
-	if (flags & SCSI_RESET) {
-		OUTB (nc_scntl1, CRST);
-		DELAY (1000);
-		return(COMPLETE);
-	}
-#endif
-
-	/*---------------------------------------------
-	**
 	**      Some shortcuts ...
 	**
 	**---------------------------------------------
@@ -3779,6 +4633,19 @@
 		return(DID_BAD_TARGET);
         }
 
+	/*---------------------------------------------
+	**
+	**	Complete the 1st TEST UNIT READY command
+	**	with error condition if the device is 
+	**	flagged NOSCAN, in order to speed up 
+	**	the boot.
+	**
+	**---------------------------------------------
+	*/
+	if (cmd->cmnd[0] == 0 && (tp->usrflag & UF_NOSCAN)) {
+		tp->usrflag &= ~UF_NOSCAN;
+		return DID_BAD_TARGET;
+	}
 
 	if (DEBUG_FLAGS & DEBUG_TINY) {
 		PRINT_ADDR(cmd);
@@ -3788,13 +4655,14 @@
 	/*---------------------------------------------------
 	**
 	**	Assign a ccb / bind cmd
-	**	If no free ccb, insert cmd into the waiting list.
+	**	If resetting or no free ccb,
+	**	insert cmd into the waiting list.
 	**
 	**----------------------------------------------------
 	*/
 	save_flags(flags); cli();
 
-        if (!(cp=ncr_get_ccb (np, cmd->target, cmd->lun))) {
+        if (np->settle_time || !(cp=ncr_get_ccb (np, cmd->target, cmd->lun))) {
 		insert_into_waiting_list(np, cmd);
 		restore_flags(flags);
 		return(DID_OK);
@@ -3803,16 +4671,14 @@
 
 	/*---------------------------------------------------
 	**
-	**	Enable tagged queue if asked by user
+	**	Enable tagged queue if asked by scsi ioctl
 	**
 	**----------------------------------------------------
 	*/
-#ifdef SCSI_NCR_TAGGED_QUEUE_DISABLED
- 	if (cmd->device && cmd->device->tagged_queue &&
-	    (lp = tp->lp[cmd->lun]) && (!lp->usetags)) {
+	if (!tp->usrtags && cmd->device && cmd->device->tagged_queue) {
+		tp->usrtags = SCSI_NCR_MAX_TAGS;
 		ncr_setmaxtags (np, tp, SCSI_NCR_MAX_TAGS);
 	}
-#endif
 
 	/*---------------------------------------------------
 	**
@@ -3820,9 +4686,10 @@
 	**
 	**----------------------------------------------------
 	*/
-
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 	bzero (&cp->phys.header.stamp, sizeof (struct tstamp));
 	cp->phys.header.stamp.start = jiffies;
+#endif
 
 	/*----------------------------------------------------
 	**
@@ -3857,7 +4724,8 @@
 
 	nego = 0;
 
-	if (cmd->lun == 0 && (tp->inqdata[2] & 0x7) >= 2 && tp->inqdata[7]) {
+	if (cmd->lun == 0 && !tp->nego_cp && 
+	    (tp->inqdata[2] & 0x7) >= 2 && tp->inqdata[7]) {
 		/*
 		**	negotiate wide transfers ?
 		*/
@@ -3874,7 +4742,7 @@
 		*/
 
 		if (!nego && !tp->period) {
-			if (SCSI_NCR_MAX_SYNC 
+			if ( 1
 #if defined (CDROM_ASYNC)
 			    && ((tp->inqdata[0] & 0x1f) != 5)
 #endif
@@ -3887,6 +4755,15 @@
 				printf ("asynchronous.\n");
 			};
 		};
+
+		/*
+		**	remember nego is pending for the target.
+		**	Avoid to start a nego for all queued commands 
+		**	when tagged command queuing is enabled.
+		*/
+
+		if (nego)
+			tp->nego_cp = cp;
 	};
 
 	/*---------------------------------------------------
@@ -3925,7 +4802,7 @@
 
 	idmsg = M_IDENTIFY | cmd->lun;
 
-	if ((cp!=&np->ccb) && (np->disc))
+	if (cp != np->ccb && ((np->disc && !(tp->usrflag & UF_NODISC)) || cp->tag))
 		idmsg |= 0x40;
 
 	msgptr = cp->scsi_smsg;
@@ -4013,7 +4890,7 @@
 	segments = ncr_scatter (cp, cp->cmd);
 
 	if (segments < 0) {
-		ncr_free_ccb(np, cp);
+		ncr_free_ccb(np, cp, cmd->target, cmd->lun);
 		restore_flags(flags);
 		return(DID_ERROR);
 	}
@@ -4028,10 +4905,12 @@
 	switch((int) cmd->cmnd[0]) {
 	case 0x08:  /*	READ(6)				08 */
 	case 0x28:  /*	READ(10)			28 */
+	case 0xA8:  /*	READ(12)			A8 */
 		xfer_direction = XferIn;
 		break;
 	case 0x0A:  /*	WRITE(6)			0A */
 	case 0x2A:  /*	WRITE(10)			2A */
+	case 0xAA:  /*	WRITE(12)			AA */
 		xfer_direction = XferOut;
 		break;
 	default:
@@ -4046,20 +4925,31 @@
 	**----------------------------------------------------
 	*/
 
+	cp->segments = segments;
+	if (!cp->data_len)
+		xfer_direction = XferNone;
+
 	switch (xfer_direction) {
+		u_long endp;
 	default:
+	case XferBoth:
+		cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_io);
+		cp->phys.header.goalp = cp->phys.header.savep;
+		break;
 	case XferIn:
-	     cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_in);
-	     cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16;
-	     break;
+		endp = NCB_SCRIPT_PHYS (np, data_in) + MAX_SCATTER*16;
+		cp->phys.header.goalp = endp + 8;
+		cp->phys.header.savep = endp - segments*16;
+		break;
 	case XferOut:
-	     cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_out);
-	     cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16;
-	     break;
+		endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16;
+		cp->phys.header.goalp = endp + 8;
+		cp->phys.header.savep = endp - segments*16;
+		break;
 	case XferNone:
-	     cp->phys.header.savep = NCB_SCRIPT_PHYS (np, no_data);
-	     cp->phys.header.goalp = cp->phys.header.savep;
-	     break;
+		cp->phys.header.savep = NCB_SCRIPT_PHYS (np, no_data);
+		cp->phys.header.goalp = cp->phys.header.savep;
+		break;
 	}
 
 	cp->phys.header.lastp = cp->phys.header.savep;
@@ -4161,12 +5051,15 @@
 		printf ("%s: queuepos=%d tryoffset=%d.\n", ncr_name (np),
 		np->squeueput,
 		(unsigned)(np->script->startpos[0]- 
-			   (NCB_SCRIPT_PHYS (np, tryloop))));
+			   (NCB_SCRIPTH_PHYS (np, tryloop))));
 
 	/*
 	**	Script processor may be waiting for reselect.
 	**	Wake it up.
 	*/
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+	if (!np->stalling)
+#endif
 	OUTB (nc_istat, SIGP);
 
 	/*
@@ -4184,28 +5077,112 @@
 /*==========================================================
 **
 **
+**	Start reset process.
+**	If reset in progress do nothing.
+**	The interrupt handler will reinitialize the chip.
+**	The timeout handler will wait for settle_time before 
+**	clearing it and so resuming command processing.
+**
+**
+**==========================================================
+*/
+static void ncr_start_reset(ncb_p np, int settle_delay)
+{
+	u_long flags;
+
+	save_flags(flags); cli();
+
+	if (!np->settle_time) {
+		if (bootverbose > 1)
+			printf("%s: resetting, command processing suspended for %d seconds\n",
+				ncr_name(np), settle_delay);
+		np->settle_time	= jiffies + settle_delay * HZ;
+		OUTB (nc_istat, SRST);
+		DELAY (1000);
+		OUTB (nc_istat, 0);
+		OUTW (nc_sien, RST);
+		OUTB (nc_scntl1, CRST);
+		DELAY (100);
+	}
+
+	restore_flags(flags);
+}
+
+/*==========================================================
+**
+**
 **	Reset the SCSI BUS.
 **	This is called from the generic SCSI driver.
 **
 **
 **==========================================================
 */
-int ncr_reset_bus (Scsi_Cmnd *cmd)
+int ncr_reset_bus (Scsi_Cmnd *cmd, int sync_reset)
 {
         struct Scsi_Host   *host      = cmd->host;
 /*	Scsi_Device        *device    = cmd->device; */
 	struct host_data   *host_data = (struct host_data *) host->hostdata;
-	ncb_p np                      = &host_data->ncb_data;
+	ncb_p np                      = host_data->ncb;
+	ccb_p cp;
 	u_long flags;
+	int found;
 
-	save_flags(flags); cli();
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+	if (np->stalling)
+		np->stalling = 0;
+#endif
 
+	save_flags(flags); cli();
+/*
+ * Return immediately if reset is in progress.
+ */
+	if (np->settle_time) {
+		restore_flags(flags);
+		return SCSI_RESET_PUNT;
+	}
+/*
+ * Start the reset process.
+ * The script processor is then assumed to be stopped.
+ * Commands will now be queued in the waiting list until a settle 
+ * delay of 2 seconds will be completed.
+ */
+	ncr_start_reset(np, 2);
+/*
+ * First, look in the wakeup list
+ */
+	for (found=0, cp=np->ccb; cp; cp=cp->link_ccb) {
+		/*
+		**	look for the ccb of this command.
+		*/
+		if (cp->host_status == HS_IDLE) continue;
+		if (cp->cmd == cmd) {
+			found = 1;
+			break;
+		}
+	}
+/*
+ * Then, look in the waiting list
+ */
+	if (!found && retrieve_from_waiting_list(0, np, cmd))
+		found = 1;
+/*
+ * Wake-up all awaiting commands with DID_RESET.
+ */
 	reset_waiting_list(np);
-	ncr_init(np, "scsi bus reset", HS_RESET);
-
-#ifndef SCSI_NCR_NO_DISCONNECT
-	np->disc = 1;
-#endif
+/*
+ * Wake-up all pending commands with HS_RESET -> DID_RESET.
+ */
+	ncr_wakeup(np, HS_RESET);
+/*
+ * If the involved command was not in a driver queue, and the 
+ * scsi driver told us reset is synchronous, and the command is not 
+ * currently in the waiting list, complete it with DID_RESET status,
+ * in order to keep it alive.
+ */
+	if (!found && sync_reset && !retrieve_from_waiting_list(0, np, cmd)) {
+		cmd->result = ScsiResult(DID_RESET, 0);
+		cmd->scsi_done(cmd);
+	}
 
 	restore_flags(flags);
 
@@ -4221,17 +5198,22 @@
 **
 **==========================================================
 */
-int ncr_abort_command (Scsi_Cmnd *cmd)
+static int ncr_abort_command (Scsi_Cmnd *cmd)
 {
         struct Scsi_Host   *host      = cmd->host;
 /*	Scsi_Device        *device    = cmd->device; */
 	struct host_data   *host_data = (struct host_data *) host->hostdata;
-	ncb_p np                      = &host_data->ncb_data;
+	ncb_p np                      = host_data->ncb;
 	ccb_p cp;
 	u_long flags;
 	int found;
 	int retv;
 
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+	if (np->stalling == 2)
+		np->stalling = 0;
+#endif
+
 	save_flags(flags); cli();
 /*
  * First, look for the scsi command in the waiting list
@@ -4246,7 +5228,7 @@
 /*
  * Then, look in the wakeup list
  */
-	for (found=0, cp=&np->ccb; cp; cp=cp->link_ccb) {
+	for (found=0, cp=np->ccb; cp; cp=cp->link_ccb) {
 		/*
 		**	look for the ccb of this command.
 		*/
@@ -4256,14 +5238,23 @@
 			break;
 		}
 	}
+
 	if (!found) {
 		restore_flags(flags);
 		return SCSI_ABORT_NOT_RUNNING;
 	}
 
+	if (np->settle_time) {
+		restore_flags(flags);
+		return SCSI_ABORT_SNOOZE;
+	}
+
 	/*
 	**	Disable reselect.
 	**      Remove it from startqueue.
+	**	Set cp->tlimit to 0. The ncr_timeout() handler will use 
+	**	this condition in order to complete the canceled command 
+	**	after the script skipped the ccb, if necessary.
 	*/
 	cp->jump_ccb.l_cmd = (SCR_JUMP);
 	if (cp->phys.header.launch.l_paddr == NCB_SCRIPT_PHYS (np, select)) {
@@ -4271,35 +5262,18 @@
 		cp->phys.header.launch.l_paddr = NCB_SCRIPT_PHYS (np, skip);
 	}
 
-	switch (cp->host_status) {
-	case HS_BUSY:
-	case HS_NEGOTIATE:
-		/*
-		** still in start queue ?
-		*/
-		if (cp->phys.header.launch.l_paddr == NCB_SCRIPT_PHYS (np, skip)) {
-			retv = SCSI_ABORT_BUSY;
-			break;
-		}
-	/* fall through */
-	case HS_DISCONNECT:
-		cp->host_status=HS_ABORTED;
-		cp->tag = 0;
-		/*
-		**	wakeup this ccb.
-		*/
-		ncr_complete (np, cp);
-		retv = SCSI_ABORT_SUCCESS;
-		break;
-	default:
-		cp->tag = 0;
-		/*
-		**	wakeup this ccb.
-		*/
-		ncr_complete (np, cp);
-		retv = SCSI_ABORT_SUCCESS;
-		break;
-	}
+	cp->tlimit = 0;
+	retv = SCSI_ABORT_PENDING;
+
+	/*
+	**      If there are no requests, the script
+	**      processor will sleep on SEL_WAIT_RESEL.
+	**      Let's wake it up, since it may have to work.
+	*/
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+	if (!np->stalling)
+#endif
+	OUTB (nc_istat, SIGP);
 
 	restore_flags(flags);
 
@@ -4325,7 +5299,6 @@
 	lcb_p lp;
 	int target, lun;
 	int i;
-	u_char scntl3;
 
 	printf("%s: releasing host resources\n", ncr_name(np));
 
@@ -4334,7 +5307,7 @@
 **	Set release_stage to 1 and wait that ncr_timeout() set it to 2.
 */
 
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 	printf("%s: stopping the timer\n", ncr_name(np));
 #endif
 	np->release_stage = 1;
@@ -4347,7 +5320,7 @@
 **	Disable chip interrupts
 */
 
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 	printf("%s: disabling chip interrupts\n", ncr_name(np));
 #endif
 	OUTW (nc_sien , 0);
@@ -4357,7 +5330,7 @@
 **	Free irq
 */
 
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 	printf("%s: freeing irq %d\n", ncr_name(np), irq);
 #endif
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
@@ -4372,28 +5345,40 @@
 
 	/*
 	**	Reset NCR chip
-	**	Preserve scntl3 for automatic clock detection.
+	**	Restore bios setting for automatic clock detection.
 	*/
 
 	printf("%s: resetting chip\n", ncr_name(np));
-	scntl3 = INB (nc_scntl3);
 	OUTB (nc_istat,  SRST);
 	DELAY (1000);
 	OUTB (nc_istat,  0   );
-	OUTB (nc_scntl3, scntl3);
+
+	OUTB(nc_dmode,	np->sv_dmode);
+	OUTB(nc_dcntl,	np->sv_dcntl);
+	OUTB(nc_ctest3,	np->sv_ctest3);
+	OUTB(nc_ctest4,	np->sv_ctest4);
+	OUTB(nc_ctest5,	np->sv_ctest5);
+	OUTB(nc_gpcntl,	np->sv_gpcntl);
+	OUTB(nc_stest2,	np->sv_stest2);
+
+	ncr_selectclock(np, np->sv_scntl3);
 
 	/*
 	**	Release Memory mapped IO region and IO mapped region
 	*/
 
 #ifndef NCR_IOMAPPED
-#ifdef DEBUG
-	printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->reg_remapped, 128);
+#ifdef DEBUG_NCR53C8XX
+	printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
+#endif
+	unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
+#ifdef DEBUG_NCR53C8XX
+	printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096);
 #endif
-	unmap_pci_mem((vm_offset_t) np->reg_remapped, (u_long) 128);
+	unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096);
 #endif
 
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 	printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
 #endif
 	release_region(np->port, 128);
@@ -4402,13 +5387,13 @@
 	**	Free allocated ccb(s)
 	*/
 
-	while ((cp=np->ccb.link_ccb) != NULL) {
-		np->ccb.link_ccb = cp->link_ccb;
+	while ((cp=np->ccb->link_ccb) != NULL) {
+		np->ccb->link_ccb = cp->link_ccb;
 		if (cp->host_status) {
 		printf("%s: shall free an active ccb (host_status=%d)\n",
 			ncr_name(np), cp->host_status);
 		}
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 	printf("%s: freeing ccb (%lx)\n", ncr_name(np), (u_long) cp);
 #endif
 		m_free(cp, sizeof(*cp));
@@ -4423,7 +5408,7 @@
 		for (lun = 0 ; lun < MAX_LUN ; lun++) {
 			lp = tp->lp[lun];
 			if (lp) {
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 	printf("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp);
 #endif
 				m_free(lp, sizeof(*lp));
@@ -4476,7 +5461,7 @@
 	**	timestamp
 	**	Optional, spare some CPU time
 	*/
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 	ncb_profile (np, cp);
 #endif
 
@@ -4487,6 +5472,16 @@
 	cmd = cp->cmd;
 	cp->cmd = NULL;
 	tp = &np->target[cmd->target];
+	lp = tp->lp[cmd->lun];
+
+	/*
+	**	We donnot queue more than 1 ccb per target 
+	**	with negotiation at any time. If this ccb was 
+	**	used for negotiation, clear this info in the tcb.
+	*/
+
+	if (cp == tp->nego_cp)
+		tp->nego_cp = 0;
 
 	/*
 	**	Check for parity errors.
@@ -4555,11 +5550,11 @@
 		*/
 		if (cmd->lun == 0 && cmd->cmnd[0] == 0x12) {
 			if (np->unit < SCSI_NCR_MAX_HOST) {
-#ifdef SCSI_NCR_FORCE_SYNC_NEGO
-				((char *) cmd->request_buffer)[7] |= INQ7_SYNC;
-#endif
-				((char *) cmd->request_buffer)[7] &=
-				(target_capabilities[np->unit].and_map[cmd->target]);
+				if (driver_setup.force_sync_nego)
+					((char *) cmd->request_buffer)[7] |= INQ7_SYNC;
+				else
+					((char *) cmd->request_buffer)[7] &=
+					(target_capabilities[np->unit].and_map[cmd->target]);
 			}
 			bcopy (	cmd->request_buffer,
 				&tp->inqdata,
@@ -4568,12 +5563,7 @@
 			/*
 			**	set number of tags
 			*/
-			lp = tp->lp[cmd->lun];
-#ifndef SCSI_NCR_TAGGED_QUEUE_DISABLED
-			if (lp && !lp->usetags) {
-				ncr_setmaxtags (np, tp, SCSI_NCR_MAX_TAGS);
-			}
-#endif
+				ncr_setmaxtags (np, tp, driver_setup.default_tags);
 			/*
 			**	prepare negotiation of synch and wide.
 			*/
@@ -4585,8 +5575,33 @@
 			tp->quirks |= QUIRK_UPDATE;
 		}
 
+		/*
+		**	Announce changes to the generic driver.
+		*/
+		if (lp) {
+			ncr_settags (tp, lp);
+			if (lp->reqlink != lp->actlink)
+				ncr_opennings (np, lp, cmd);
+		};
+
 		tp->bytes     += cp->data_len;
 		tp->transfers ++;
+
+		/*
+		**	If tags was reduced due to queue full,
+		**	increase tags if 100 good status received.
+		*/
+		if (tp->numtags < tp->maxtags) {
+			++tp->num_good;
+			if (tp->num_good >= 100) {
+				tp->num_good = 0;
+				++tp->numtags;
+				if (tp->numtags == 1) {
+					PRINT_ADDR(cmd);
+					printf("tagged command queueing resumed\n");
+				}
+			}
+		}
 	} else if ((cp->host_status == HS_COMPLETE)
 		&& (cp->scsi_status == (S_SENSE|S_GOOD) ||
 		    cp->scsi_status == (S_SENSE|S_CHECK_COND))) {
@@ -4612,6 +5627,29 @@
 		*/
 		cmd->result = ScsiResult(DID_OK, cp->scsi_status);
 
+	} else if ((cp->host_status == HS_COMPLETE)
+		&& (cp->scsi_status == S_QUEUE_FULL)) {
+
+		/*
+		**   Target is stuffed.
+		*/
+		cmd->result = ScsiResult(DID_OK, cp->scsi_status);
+
+		/*
+		**  Suspend tagged queuing and start good status counter.
+		**  Announce changes to the generic driver.
+		*/
+		if (tp->numtags) {
+			PRINT_ADDR(cmd);
+			printf("QUEUE FULL! suspending tagged command queueing\n");
+			tp->numtags	= 0;
+			tp->num_good	= 0;
+			if (lp) {
+				ncr_settags (tp, lp);
+				if (lp->reqlink != lp->actlink)
+					ncr_opennings (np, lp, cmd);
+			};
+		}
 	} else if ((cp->host_status == HS_SEL_TIMEOUT)
 		|| (cp->host_status == HS_TIMEOUT)) {
 
@@ -4680,7 +5718,7 @@
 	/*
 	**	Free this ccb
 	*/
-	ncr_free_ccb (np, cp);
+	ncr_free_ccb (np, cp, cmd->target, cmd->lun);
 
 	/*
 	**	requeue awaiting scsi commands
@@ -4713,7 +5751,7 @@
 	**	complete all jobs that are not IDLE.
 	*/
 
-	ccb_p cp = &np->ccb;
+	ccb_p cp = np->ccb;
 	while (cp) {
 		switch (cp->host_status) {
 
@@ -4751,11 +5789,6 @@
 void ncr_init (ncb_p np, char * msg, u_long code)
 {
 	int	i;
-	u_long	usrsync;
-	u_char	usrwide;
-#if 0
-	u_char	burstlen;
-#endif
 
 	/*
 	**	Reset chip.
@@ -4768,7 +5801,7 @@
 	**	Message.
 	*/
 
-	if (msg) printf ("%s: restart (%s).\n", ncr_name (np), msg);
+	if (msg) printf (KERN_INFO "%s: restart (%s).\n", ncr_name (np), msg);
 
 	/*
 	**	Clear Start Queue
@@ -4779,10 +5812,9 @@
 	/*
 	**	Start at first entry.
 	*/
-
 	np->squeueput = 0;
-	np->script->startpos[0] = NCB_SCRIPT_PHYS (np, tryloop);
-	np->script->start0  [0] = SCR_INT ^ IFFALSE (0);
+	np->script0->startpos[0] = NCB_SCRIPTH_PHYS (np, tryloop);
+	np->script0->start0  [0] = SCR_INT ^ IFFALSE (0);
 
 	/*
 	**	Wakeup all pending jobs.
@@ -4790,122 +5822,73 @@
 	ncr_wakeup (np, code);
 
 	/*
-	**	Remove Reset, abort ...
-	*/
-	OUTB (nc_istat,  0      );
-
-	/*
 	**	Init chip.
 	*/
-/**	NCR53C810			**/
-	if (ChipDevice == PCI_DEVICE_ID_NCR_53C810 && ChipVersion == 0) {
-		OUTB(nc_dmode, 0x80);	/* Set 8-transfer burst */
-	}
-	else
-/**	NCR53C815			**/
-	if (ChipDevice == PCI_DEVICE_ID_NCR_53C815) {
-		OUTB(nc_dmode, 0x80);	/* Set 8-transfer burst */
-	}
-	else
-/**	NCR53C825			**/
-	if (ChipDevice == PCI_DEVICE_ID_NCR_53C825 && ChipVersion == 0) {
-		OUTB(nc_dmode, 0x80);	/* Set 8-transfer burst */
-	}
-	else
-/**	NCR53C810A or NCR53C860		**/
-	if ((ChipDevice == PCI_DEVICE_ID_NCR_53C810 && ChipVersion >= 0x10) ||
-	    ChipDevice == PCI_DEVICE_ID_NCR_53C860) {
-		OUTB(nc_dmode, 0xc0);	/* Set 16-transfer burst */
-#if 0
-		OUTB(nc_ctest3, 0x01);	/* Set write and invalidate */
-		OUTB(nc_dcntl, 0xa1);	/* Cache line size enable, */
-					/* pre-fetch enable and 700 comp */
-#endif
-	}
-	else
-/**	NCR53C825A or NCR53C875		**/
-	if ((ChipDevice == PCI_DEVICE_ID_NCR_53C825 && ChipVersion >= 0x10) ||
-	    ChipDevice == PCI_DEVICE_ID_NCR_53C875) {
-		OUTB(nc_dmode, 0xc0);	/* Set 16-transfer burst */
-#if 0
-		OUTB(nc_ctest5, 0x04);	/* Set DMA FIFO to 88 */
-		OUTB(nc_ctest5, 0x24);	/* Set DMA FIFO to 536 */
-		OUTB(nc_dmode, 0x40);	/* Set 64-transfer burst */
-		OUTB(nc_ctest3, 0x01);	/* Set write and invalidate */
-		OUTB(nc_dcntl, 0x81);	/* Cache line size enable and 700 comp*/
-#endif
-	}
-/**	OTHERS				**/
-	else {
-		OUTB(nc_dmode, 0xc0);	/* Set 16-transfer burst */
-	}
-#if 0
-	burstlen = 0xc0;
-#endif
-
-#ifdef SCSI_NCR_DISABLE_PARITY_CHECK
-	OUTB (nc_scntl0, 0xc0   );      /*  full arb., (no parity)           */
-#else
-	OUTB (nc_scntl0, 0xca   );      /*  full arb., ena parity, par->ATN  */
-#endif
 
-	OUTB (nc_scntl1, 0x00	);	/*  odd parity, and remove CRST!!    */
-	OUTB (nc_scntl3, np->rv_scntl3);/*  timing prescaler		     */
-	OUTB (nc_scid  , RRE|np->myaddr);/*  host adapter SCSI address       */
-	OUTW (nc_respid, 1ul<<np->myaddr);/*  id to respond to		     */
-	OUTB (nc_istat , SIGP	);	/*  Signal Process		     */
-#if 0
-	OUTB (nc_dmode , burstlen);	/*  Burst length = 2 .. 16 transfers */
-#endif
-	OUTB (nc_dcntl , NOCOM  );      /*  no single step mode, protect SFBR*/
+	OUTB (nc_istat,  0x00   );	/*  Remove Reset, abort */
+	OUTB (nc_scntl0, np->rv_scntl0 | 0xc0);
+					/*  full arb., ena parity, par->ATN  */
+	OUTB (nc_scntl1, 0x00);		/*  odd parity, and remove CRST!! */
+
+	ncr_selectclock(np, np->rv_scntl3);	/* Select SCSI clock */
+
+	OUTB (nc_scid  , RRE|np->myaddr);	/* Adapter SCSI address */
+	OUTW (nc_respid, 1ul<<np->myaddr);	/* Id to respond to */
+	OUTB (nc_istat , SIGP	);		/*  Signal Process */
+	OUTB (nc_dmode , np->rv_dmode);		/* Burst length, dma mode */
+	OUTB (nc_ctest5, np->rv_ctest5);	/* Large fifo + large burst */
+
+	OUTB (nc_dcntl , NOCOM|np->rv_dcntl);	/* Protect SFBR */
+	OUTB (nc_ctest3, np->rv_ctest3);	/* Write and invalidate */
+	OUTB (nc_ctest4, np->rv_ctest4);	/* Master parity checking */
+
+	OUTB (nc_stest2, EXT|np->rv_stest2);	/* Extended Sreq/Sack filtering */
+	OUTB (nc_stest3, TE);			/* TolerANT enable */
+	OUTB (nc_stime0, 0x0d	);		/* HTH disabled  STO 0.4 sec. */
 
-#ifdef SCSI_NCR_DISABLE_MPARITY_CHECK
-	OUTB (nc_ctest4, 0x00	);	/*  disable master parity checking   */
-#else
-	OUTB (nc_ctest4, 0x08	);	/*  enable master parity checking    */
-#endif
+	/*
+	**	Disable disconnects.
+	*/
 
-	OUTB (nc_stest2, EXT    );	/*  Extended Sreq/Sack filtering     */
-	OUTB (nc_stest3, TE     );	/*  TolerANT enable		     */
-	OUTB (nc_stime0, 0x0d	);	/*  HTH = disable  STO = 0.4 sec.    */
-					/*  0.25 sec recommended for scsi 1  */
+	np->disc = 0;
 
 	/*
-	**	Reinitialize usrsync.
-	**	Have to renegotiate synch mode.
+	**    Enable GPIO0 pin for writing if LED support.
 	*/
 
-	usrsync = 255;
+	if (np->features & FE_LED0) {
+		OUTOFFB (nc_gpcntl, 0x01);
+	}
 
-#ifndef SCSI_NCR_FORCE_ASYNCHRONOUS
-	if (SCSI_NCR_MAX_SYNC) {
-		u_long period;
-		period =1000000/SCSI_NCR_MAX_SYNC; /* ns = 10e6 / kHz */
-		if (period <= 11 * np->ns_sync) {
-			if (period < 4 * np->ns_sync)
-				usrsync = np->ns_sync;
-			else
-				usrsync = period / 4;
-		};
-	};
-#endif
+	/*
+	**    Upload the script into on-board RAM
+	*/
+	if (np->vaddr2) {
+		if (bootverbose)
+			printf ("%s: copying script fragments into the on-board RAM ...\n", ncr_name(np));
+		bcopy(np->script0, np->script, sizeof(struct script));
+	}
 
 	/*
-	**	Reinitialize usrwide.
-	**	Have to renegotiate wide mode.
+	**      enable ints
 	*/
 
-	usrwide = (SCSI_NCR_MAX_WIDE);
-	if (usrwide > np->maxwide) usrwide=np->maxwide;
+	OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST);
+	OUTB (nc_dien , MDPE|BF|ABRT|SSI|SIR|IID);
 
 	/*
-	**	Disable disconnects.
+	**	For 895/6 enable SBMC interrupt and save current SCSI bus mode.
 	*/
-
-	np->disc = 0;
+	if (np->features & FE_ULTRA2) {
+		OUTONW (nc_sien, SBMC);
+		np->scsi_mode = INB (nc_stest4) & SMODE;
+	}
 
 	/*
 	**	Fill in target structure.
+	**	Reinitialize usrsync.
+	**	Reinitialize usrwide.
+	**	Prepare sync negotiation according to actual SCSI bus mode.
 	*/
 
 	for (i=0;i<MAX_TARGET;i++) {
@@ -4914,20 +5897,23 @@
 		tp->sval    = 0;
 		tp->wval    = np->rv_scntl3;
 
-		tp->usrsync = usrsync;
-		tp->usrwide = usrwide;
+		if (tp->usrsync != 255) {
+			if (tp->usrsync <= np->maxsync) {
+				if (tp->usrsync < np->minsync) {
+					tp->usrsync = np->minsync;
+				}
+			}
+			else
+				tp->usrsync = 255;
+		};
+
+		if (tp->usrwide > np->maxwide)
+			tp->usrwide = np->maxwide;
 
 		ncr_negotiate (np, tp);
 	}
 
 	/*
-	**      enable ints
-	*/
-
-	OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST);
-	OUTB (nc_dien , MDPE|BF|ABRT|SSI|SIR|IID);
-
-	/*
 	**    Start script processor.
 	*/
 
@@ -4950,7 +5936,13 @@
 
 	u_long minsync = tp->usrsync;
 
-	if (minsync < 25) minsync=25;
+	/*
+	**	SCSI bus mode limit
+	*/
+
+	if (np->scsi_mode && np->scsi_mode == SMODE_SE) {
+		if (minsync < 12) minsync = 12;
+	}
 
 	/*
 	**	if not scsi 2
@@ -4964,18 +5956,18 @@
 	**	our limit ..
 	*/
 
-	if (minsync < np->ns_sync)
-		minsync = np->ns_sync;
+	if (minsync < np->minsync)
+		minsync = np->minsync;
 
 	/*
 	**	divider limit
 	*/
 
-	if (minsync > (np->ns_sync * 11) / 4)
+	if (minsync > np->maxsync)
 		minsync = 255;
 
 	tp->minsync = minsync;
-	tp->maxoffs = (minsync<255 ? 8 : 0);
+	tp->maxoffs = (minsync<255 ? np->maxoffs : 0);
 
 	/*
 	**	period=0: has to negotiate sync transfer
@@ -4991,16 +5983,120 @@
 
 /*==========================================================
 **
+**	Get clock factor and sync divisor for a given 
+**	synchronous factor period.
+**	Returns the clock factor (in sxfer) and scntl3 
+**	synchronous divisor field.
+**
+**==========================================================
+*/
+
+static void ncr_getsync(ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p)
+{
+	u_long	clk = np->clock_khz;	/* SCSI clock frequency in kHz	*/
+	int	div = np->clock_divn;	/* Number of divisors supported	*/
+	u_long	fak;			/* Sync factor in sxfer		*/
+	u_long	per;			/* Period in tenths of ns	*/
+	u_long	kpc;			/* (per * clk)			*/
+
+	/*
+	**	Compute the synchronous period in tenths of nano-seconds
+	*/
+	if	(sfac <= 10)	per = 250;
+	else if	(sfac == 11)	per = 303;
+	else if	(sfac == 12)	per = 500;
+	else			per = 40 * sfac;
+
+	/*
+	**	Look for the greatest clock divisor that allows an 
+	**	input speed faster than the period.
+	*/
+	kpc = per * clk;
+	while (--div >= 0)
+		if (kpc >= (div_10M[div] << 2)) break;
+
+	/*
+	**	Calculate the lowest clock factor that allows an output 
+	**	speed not faster than the period.
+	*/
+	fak = (kpc - 1) / div_10M[div] + 1;
+
+#if 0	/* This optimization does not seem very usefull */
+
+	per = (fak * div_10M[div]) / clk;
+
+	/*
+	**	Why not to try the immediate lower divisor and to choose 
+	**	the one that allows the fastest output speed ?
+	**	We dont want input speed too much greater than output speed.
+	*/
+	if (div >= 1 && fak < 8) {
+		u_long fak2, per2;
+		fak2 = (kpc - 1) / div_10M[div-1] + 1;
+		per2 = (fak2 * div_10M[div-1]) / clk;
+		if (per2 < per && fak2 <= 8) {
+			fak = fak2;
+			per = per2;
+			--div;
+		}
+	}
+#endif
+
+	if (fak < 4) fak = 4;	/* Should never happen, too bad ... */
+
+	/*
+	**	Compute and return sync parameters for the ncr
+	*/
+	*fakp		= fak - 4;
+	*scntl3p	= ((div+1) << 4) + (sfac < 25 ? 0x80 : 0);
+}
+
+
+/*==========================================================
+**
+**	Set actual values, sync status and patch all ccbs of 
+**	a target according to new sync/wide agreement.
+**
+**==========================================================
+*/
+
+static void ncr_set_sync_wide_status (ncb_p np, u_char target)
+{
+	ccb_p cp;
+	tcb_p tp = &np->target[target];
+
+	/*
+	**	set actual value and sync_status
+	*/
+	OUTB (nc_sxfer, tp->sval);
+	np->sync_st = tp->sval;
+	OUTB (nc_scntl3, tp->wval);
+	np->wide_st = tp->wval;
+
+	/*
+	**	patch ALL ccbs of this target.
+	*/
+	for (cp = np->ccb; cp; cp = cp->link_ccb) {
+		if (!cp->cmd) continue;
+		if (cp->cmd->target != target) continue;
+		cp->sync_status = tp->sval;
+		cp->wide_status = tp->wval;
+	};
+}
+
+/*==========================================================
+**
 **	Switch sync mode for current job and it's target
 **
 **==========================================================
 */
 
-static void ncr_setsync (ncb_p np, ccb_p cp, u_char sxfer)
+static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer)
 {
 	Scsi_Cmnd *cmd;
 	tcb_p tp;
-	u_char target = INB (nc_ctest0)&7;
+	u_char target = INB (nc_ctest0) & 0x0f;
+	u_char idiv;
 
 	assert (cp);
 	if (!cp) return;
@@ -5011,57 +6107,81 @@
 	assert (target == (cmd->target & 0xf));
 
 	tp = &np->target[target];
-	tp->period= sxfer&0xf ? ((sxfer>>5)+4) * np->ns_sync : 0xffff;
 
-	if (tp->sval == sxfer) return;
+	if (!scntl3 || !(sxfer & 0x1f))
+		scntl3 = np->rv_scntl3;
+	scntl3 = (scntl3 & 0xf0) | (tp->wval & EWS) | (np->rv_scntl3 & 0x07);
+
+	/*
+	**	Deduce the value of controller sync period from scntl3.
+	**	period is in tenths of nano-seconds.
+	*/
+
+	idiv = ((scntl3 >> 4) & 0x7);
+	if ((sxfer & 0x1f) && idiv)
+		tp->period = (((sxfer>>5)+4)*div_10M[idiv-1])/np->clock_khz;
+	else
+		tp->period = 0xffff;
+
+	/*
+	**	 Stop there if sync parameters are unchanged
+	*/
+	if (tp->sval == sxfer && tp->wval == scntl3) return;
 	tp->sval = sxfer;
+	tp->wval = scntl3;
 
 	/*
 	**	Bells and whistles   ;-)
 	*/
 	PRINT_ADDR(cmd);
-	if (sxfer & 0x0f) {
+	if (sxfer & 0x01f) {
+		unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0);
+		unsigned mb10 = (f10 + tp->period/2) / tp->period;
+		char *scsi;
+
 		/*
 		**  Disable extended Sreq/Sack filtering
 		*/
-		if (tp->period <= 200) OUTB (nc_stest2, 0);
+		if (tp->period <= 2000) OUTOFFB (nc_stest2, EXT);
 
-		printf ("%s%dns (%d Mb/sec) offset %d.\n",
-			tp->period<200 ? "FAST SCSI-2 ":"",
-			tp->period,
-			(((tp->wval & EWS)? 2:1)*1000+tp->period/2)/tp->period,
-			sxfer & 0x0f);
-	} else  printf ("asynchronous.\n");
+		/*
+		**	Bells and whistles   ;-)
+		*/
+		if	(tp->period < 500)	scsi = "FAST-40";
+		else if	(tp->period < 1000)	scsi = "FAST-20";
+		else if	(tp->period < 2000)	scsi = "FAST-10";
+		else				scsi = "SLOW";
 
-	/*
-	**	set actual value and sync_status
-	*/
-	OUTB (nc_sxfer, sxfer);
-	np->sync_st = sxfer;
+		printf ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi,
+			tp->widedone > 1 ? "WIDE " : "",
+			mb10 / 10, mb10 % 10, tp->period / 10, sxfer & 0x1f);
+	} else
+		printf ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : "");
 
 	/*
+	**	set actual value and sync_status
 	**	patch ALL ccbs of this target.
 	*/
-	for (cp = &np->ccb; cp; cp = cp->link_ccb) {
-		if (!cp->cmd) continue;
-		if (cp->cmd->target != target) continue;
-		cp->sync_status = sxfer;
-	};
+	ncr_set_sync_wide_status(np, target);
 }
 
 /*==========================================================
 **
 **	Switch wide mode for current job and it's target
+**	SCSI specs say: a SCSI device that accepts a WDTR 
+**	message shall reset the synchronous agreement to 
+**	asynchronous mode.
 **
 **==========================================================
 */
 
-static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide)
+static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide, u_char ack)
 {
 	Scsi_Cmnd *cmd;
-	u_short target = INB (nc_ctest0)&7;
+	u_short target = INB (nc_ctest0) & 0x0f;
 	tcb_p tp;
-	u_char	scntl3 = np->rv_scntl3 | (wide ? EWS : 0);
+	u_char	scntl3;
+	u_char	sxfer;
 
 	assert (cp);
 	if (!cp) return;
@@ -5073,32 +6193,33 @@
 
 	tp = &np->target[target];
 	tp->widedone  =  wide+1;
-	if (tp->wval == scntl3) return;
-	tp->wval = scntl3;
+	scntl3 = (tp->wval & (~EWS)) | (wide ? EWS : 0);
+
+	sxfer = ack ? 0 : tp->sval;
 
 	/*
-	**	Bells and whistles   ;-)
+	**	 Stop there if sync/wide parameters are unchanged
 	*/
-	PRINT_ADDR(cmd);
-	if (scntl3 & EWS)
-		printf ("WIDE SCSI (16 bit) enabled.\n");
-	else
-		printf ("WIDE SCSI disabled.\n");
+	if (tp->sval == sxfer && tp->wval == scntl3) return;
+	tp->sval = sxfer;
+	tp->wval = scntl3;
 
 	/*
-	**	set actual value and sync_status
+	**	Bells and whistles   ;-)
 	*/
-	OUTB (nc_scntl3, scntl3);
-	np->wide_st = scntl3;
+	if (bootverbose >= 2) {
+		PRINT_ADDR(cmd);
+		if (scntl3 & EWS)
+			printf ("WIDE SCSI (16 bit) enabled.\n");
+		else
+			printf ("WIDE SCSI disabled.\n");
+	}
 
 	/*
+	**	set actual value and sync_status
 	**	patch ALL ccbs of this target.
 	*/
-	for (cp = &np->ccb; cp; cp = cp->link_ccb) {
-		if (!cp->cmd) continue;
-		if (cp->cmd->target != target) continue;
-		cp->wide_status = scntl3;
-	};
+	ncr_set_sync_wide_status(np, target);
 }
 
 /*==========================================================
@@ -5108,19 +6229,32 @@
 **==========================================================
 */
 
-static void ncr_setmaxtags (ncb_p np, tcb_p tp, u_long usrtags)
+static void ncr_setmaxtags (ncb_p np, tcb_p tp, u_long numtags)
 {
 	int l;
-	tp->usrtags = usrtags;
+	if (numtags > tp->usrtags)
+		numtags = tp->usrtags;
+	tp->numtags = numtags;
+	tp->maxtags = numtags;
+
 	for (l=0; l<MAX_LUN; l++) {
 		lcb_p lp;
+		u_char wastags;
+
 		if (!tp) break;
 		lp=tp->lp[l];
 		if (!lp) continue;
+
+		wastags = lp->usetags;
 		ncr_settags (tp, lp);
-		if (lp->usetags > 0) {
+
+		if (numtags > 1 && lp->reqccbs > 1) {
+			PRINT_LUN(np, tp - np->target, l);
+			printf("using tagged command queueing, up to %ld cmds/lun\n", numtags);
+		}
+		else if (numtags <= 1 && wastags) {
 			PRINT_LUN(np, tp - np->target, l);
-			printf("using tagged command queueing, up to %d cmds/lun\n", lp->usetags);
+			printf("disabling tagged command queueing\n");
 		}
 	};
 }
@@ -5139,8 +6273,8 @@
 	*/
 	if ((  tp->inqdata[2] & 0x7) >= 2 &&
 	    (  tp->inqdata[7] & INQ7_QUEUE) && ((tp->inqdata[0] & 0x1f)==0x00)
-		&& tp->usrtags) {
-		reqtags = tp->usrtags;
+		&& tp->numtags > 1) {
+		reqtags = tp->numtags;
 		if (lp->actlink <= 1)
 			lp->usetags=reqtags;
 	} else {
@@ -5171,7 +6305,7 @@
 **----------------------------------------------------
 */
 
-#ifdef SCSI_NCR_USER_COMMAND
+#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
 
 static void ncr_usercmd (ncb_p np)
 {
@@ -5196,13 +6330,13 @@
 			np->user.data = SCSI_NCR_MAX_TAGS;
 		for (t=0; t<MAX_TARGET; t++) {
 			if (!((np->user.target>>t)&1)) continue;
+			np->target[t].usrtags = np->user.data;
 			ncr_setmaxtags (np, &np->target[t], np->user.data);
 		};
-		np->disc = 1;
 		break;
 
 	case UC_SETDEBUG:
-#ifdef SCSI_NCR_DEBUG
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
 		ncr_debug = np->user.data;
 #endif
 		break;
@@ -5234,12 +6368,106 @@
 	case UC_CLEARPROF:
 		bzero(&np->profile, sizeof(np->profile));
 		break;
+#ifdef	UC_DEBUG_ERROR_RECOVERY
+	case UC_DEBUG_ERROR_RECOVERY:
+		np->debug_error_recovery = np->user.data;
+		break;
+#endif
 	}
 	np->user.cmd=0;
 }
 #endif
 
 
+/*=====================================================================
+**
+**    Embedded error recovery debugging code.
+**
+**=====================================================================
+**
+**    This code is conditionned by SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT.
+**    It only can be enabled after boot-up with a control command.
+**
+**    Every 30 seconds the timer handler of the driver decides to 
+**    change the behaviour of the driver in order to trigger errors.
+**
+**    If last command was "debug_error_recovery sge", the driver 
+**    sets sync offset of all targets that use sync transfers to 2, 
+**    and so hopes a SCSI gross error at the next read operation.
+**
+**    If last command was "debug_error_recovery abort", the driver 
+**    does not signal new scsi commands to the script processor, until 
+**    it is asked to abort or reset a command by the mid-level driver.
+**
+**    If last command was "debug_error_recovery reset", the driver 
+**    does not signal new scsi commands to the script processor, until 
+**    it is asked to reset a command by the mid-level driver.
+**
+**    If last command was "debug_error_recovery parity", the driver 
+**    will assert ATN on the next DATA IN phase mismatch, and so will 
+**    behave as if a parity error had been detected.
+**
+**    The command "debug_error_recovery none" makes the driver behave 
+**    normaly.
+**
+**=====================================================================
+*/
+
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+static void ncr_trigger_errors (ncb_p np)
+{
+	/*
+	** 	If np->debug_error_recovery is not zero, we want to 
+	**	simulate common errors in order to test error recovery.
+	*/
+	do {
+		static u_long last = 0l;
+
+		if (!np->debug_error_recovery)
+			break;
+		if (!last)
+			last = jiffies;
+		else if (jiffies < last + 30*HZ)
+			break;
+		last = jiffies;
+		/*
+		 * This one triggers SCSI gross errors.
+		 */
+		if (np->debug_error_recovery == 1) {
+			int i;
+			printf("%s: testing error recovery from SCSI gross error...\n", ncr_name(np));
+			for (i = 0 ; i < MAX_TARGET ; i++) {
+				if (np->target[i].sval & 0x1f) {
+					np->target[i].sval &= ~0x1f;
+					np->target[i].sval += 2;
+				}
+			}
+		}
+		/*
+		 * This one triggers abort from the mid-level driver.
+		 */
+		else if (np->debug_error_recovery == 2) {
+			printf("%s: testing error recovery from mid-level driver abort()...\n", ncr_name(np));
+			np->stalling = 2;
+		}
+		/*
+		 * This one triggers reset from the mid-level driver.
+		 */
+		else if (np->debug_error_recovery == 3) {
+			printf("%s: testing error recovery from mid-level driver reset()...\n", ncr_name(np));
+			np->stalling = 3;
+		}
+		/*
+		 * This one set ATN on phase mismatch in DATA IN phase and so 
+		 * will behave as on scsi parity error detected.
+		 */
+		else if (np->debug_error_recovery == 4) {
+			printf("%s: testing data in parity error...\n", ncr_name(np));
+			np->assert_atn = 1;
+		}
+	} while (0);
+}
+#endif
 
 /*==========================================================
 **
@@ -5267,7 +6495,7 @@
 	**	If release process in progress, let's go
 	**	Set the release stage from 1 to 2 to synchronize
 	**	with the release process.
-	**/
+	*/
 
 	if (np->release_stage) {
 		if (np->release_stage == 1) np->release_stage = 2;
@@ -5282,7 +6510,33 @@
 
 	add_timer(&np->timer);
 
-	if (np->lasttime + HZ < thistime) {
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+	ncr_trigger_errors (np);
+#endif
+
+	/*
+	**	If we are resetting the ncr, wait for settle_time before 
+	**	clearing it. Then command processing will be resumed.
+	*/
+	if (np->settle_time) {
+		if (np->settle_time <= thistime) {
+			if (bootverbose > 1)
+				printf("%s: command processing resumed\n", ncr_name(np));
+			save_flags(flags); cli();
+			np->settle_time	= 0;
+			np->disc	= 1;
+			requeue_waiting_list(np);
+			restore_flags(flags);
+		}
+		return;
+	}
+
+	/*
+	**	Since the generic scsi driver only allows us 0.5 second 
+	**	to perform abort of a command, we must look at ccbs about 
+	**	every 0.25 second.
+	*/
+	if (np->lasttime + (HZ>>2) <= thistime) {
 		/*
 		**	block ncr interrupts
 		*/
@@ -5311,44 +6565,15 @@
 		t = (thistime - np->heartbeat) / HZ;
 
 		if (t<2) np->latetime=0; else np->latetime++;
-		if (np->latetime>5) {
-			/*
-			**      If there are no requests, the script
-			**      processor will sleep on SEL_WAIT_RESEL.
-			**      But we have to check whether it died.
-			**      Let's wake it up.
-			*/
-			OUTB (nc_istat, SIGP);
-		}
-		if (np->latetime>10) {
-			/*
-			**	Although we tried to wake it up,
-			**	the script processor didn't respond.
-			**
-			**	May be a target is hanging,
-			**	or another initator lets a tape device
-			**	rewind with disconnect disabled :-(
-			**
-			**	We won't accept that.
-			*/
-			if (INB (nc_sbcl) & CBSY)
-				OUTB (nc_scntl1, CRST);
-			DELAY (1000);
-			ncr_init (np, "ncr dead ?", HS_TIMEOUT);
-#ifndef SCSI_NCR_NO_DISCONNECT
-			np->disc = 1;
-#endif
-			np->heartbeat = thistime;
-		}
 
 		/*----------------------------------------------------
 		**
-		**	should handle ccb timeouts
-		**	Let the middle scsi driver manage timeouts.
+		**	handle ccb timeouts
+		**
 		**----------------------------------------------------
 		*/
 
-		for (cp=&np->ccb; cp; cp=cp->link_ccb) {
+		for (cp=np->ccb; cp; cp=cp->link_ccb) {
 			/*
 			**	look for timed out ccbs.
 			*/
@@ -5357,7 +6582,7 @@
 			/*
 			**	Have to force ordered tag to avoid timeouts
 			*/
-			if (cp->cmd && cp->tlimit <= 
+			if (cp->cmd && cp->tlimit && cp->tlimit <= 
 				thistime + NCR_TIMEOUT_INCREASE + SCSI_NCR_TIMEOUT_ALERT) {
 				lcb_p lp;
 				lp = np->target[cp->cmd->target].lp[cp->cmd->lun];
@@ -5365,24 +6590,14 @@
 					lp->force_ordered_tag = 1;
 				}
 			}
-/*
-**	Let the middle scsi driver manage timeouts
-*/
-#if 0
-			if (cp->tlimit > thistime) continue;
-
 			/*
-			**	Disable reselect.
-			**      Remove it from startqueue.
+			**	ncr_abort_command() cannot complete canceled 
+			**	commands immediately. It sets tlimit to zero 
+			**	and ask the script to skip the scsi process if 
+			**	necessary. We have to complete this work here.
 			*/
-			cp->jump_ccb.l_cmd = (SCR_JUMP);
-			if (cp->phys.header.launch.l_paddr ==
-				NCB_SCRIPT_PHYS (np, select)) {
-				printf ("%s: timeout ccb=%p (skip)\n",
-					ncr_name (np), cp);
-				cp->phys.header.launch.l_paddr
-				= NCB_SCRIPT_PHYS (np, skip);
-			};
+
+			if (cp->tlimit) continue;
 
 			switch (cp->host_status) {
 
@@ -5397,7 +6612,7 @@
 
 				/* fall through */
 			case HS_DISCONNECT:
-				cp->host_status=HS_TIMEOUT;
+				cp->host_status=HS_ABORTED;
 			};
 			cp->tag = 0;
 
@@ -5405,7 +6620,11 @@
 			**	wakeup this ccb.
 			*/
 			ncr_complete (np, cp);
+
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+			if (!np->stalling)
 #endif
+			OUTB (nc_istat, SIGP);
 		}
 		restore_flags(flags);
 	}
@@ -5425,43 +6644,146 @@
 #endif /* SCSI_NCR_BROKEN_INTR */
 }
 
-/*==========================================================
-**
+/*==========================================================
+**
+**	log message for real hard errors
+**
+**	"ncr0 targ 0?: ERROR (ds:si) (so-si-sd) (sxfer/scntl3) @ name (dsp:dbc)."
+**	"	      reg: r0 r1 r2 r3 r4 r5 r6 ..... rf."
+**
+**	exception register:
+**		ds:	dstat
+**		si:	sist
+**
+**	SCSI bus lines:
+**		so:	control lines as driver by NCR.
+**		si:	control lines as seen by NCR.
+**		sd:	scsi data lines as seen by NCR.
+**
+**	wide/fastmode:
+**		sxfer:	(see the manual)
+**		scntl3:	(see the manual)
+**
+**	current script command:
+**		dsp:	script adress (relative to start of script).
+**		dbc:	first word of script command.
+**
+**	First 16 register of the chip:
+**		r0..rf
+**
+**==========================================================
+*/
+
+static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat)
+{
+	u_int32	dsp;
+	int	script_ofs;
+	int	script_size;
+	char	*script_name;
+	u_char	*script_base;
+	int	i;
+
+	dsp	= INL (nc_dsp);
+
+	if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) {
+		script_ofs	= dsp - np->p_script;
+		script_size	= sizeof(struct script);
+		script_base	= (u_char *) np->script;
+		script_name	= "script";
+	}
+	else {
+		script_ofs	= dsp - np->p_scripth;
+		script_size	= sizeof(struct scripth);
+		script_base	= (u_char *) np->scripth;
+		script_name	= "scripth";
+	}
+
+	printf ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ %s (%x:%08x).\n",
+		ncr_name (np), (unsigned)INB (nc_ctest0)&0x0f, dstat, sist,
+		(unsigned)INB (nc_socl), (unsigned)INB (nc_sbcl), (unsigned)INB (nc_sbdl),
+		(unsigned)INB (nc_sxfer),(unsigned)INB (nc_scntl3), script_name, script_ofs,
+		(unsigned)INL (nc_dbc));
+
+	if (((script_ofs & 3) == 0) &&
+	    (unsigned)script_ofs < script_size) {
+		printf ("%s: script cmd = %08x\n", ncr_name(np),
+			(int) *(ncrcmd *)(script_base + script_ofs));
+	}
+
+        printf ("%s: regdump:", ncr_name(np));
+        for (i=0; i<16;i++)
+            printf (" %02x", (unsigned)INB_OFF(i));
+        printf (".\n");
+}
+
+/*============================================================
 **
 **	ncr chip exception handler.
 **
+**============================================================
 **
-**==========================================================
+**	In normal cases, interrupt conditions occur one at a 
+**	time. The ncr is able to stack in some extra registers 
+**	other interrupts that will occurs after the first one.
+**	But severall interrupts may occur at the same time.
+**
+**	We probably should only try to deal with the normal 
+**	case, but it seems that multiple interrupts occur in 
+**	some cases that are not abnormal at all.
+**
+**	The most frequent interrupt condition is Phase Mismatch.
+**	We should want to service this interrupt quickly.
+**	A SCSI parity error may be delivered at the same time.
+**	The SIR interrupt is not very frequent in this driver, 
+**	since the INTFLY is likely used for command completion 
+**	signaling.
+**	The Selection Timeout interrupt may be triggered with 
+**	IID and/or UDC.
+**	The SBMC interrupt (SCSI Bus Mode Change) may probably 
+**	occur at any time.
+**
+**	This handler try to deal as cleverly as possible with all
+**	the above.
+**
+**============================================================
 */
 
 void ncr_exception (ncb_p np)
 {
 	u_char	istat, dstat;
 	u_short	sist;
-	u_int32	dsp, dsa;
-	int	script_ofs;
 	int	i;
 
 	/*
 	**	interrupt on the fly ?
 	*/
 	while ((istat = INB (nc_istat)) & INTF) {
-		if (DEBUG_FLAGS & DEBUG_TINY) printf ("F");
+		if (DEBUG_FLAGS & DEBUG_TINY) printf ("F ");
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+	if (np->stalling)
+		OUTB (nc_istat, INTF);
+	else
+#endif
 		OUTB (nc_istat, (istat & SIGP) | INTF);
 		np->profile.num_fly++;
 		ncr_wakeup (np, 0);
 	};
 
-	if (!(istat & (SIP|DIP))) return;
+	if (!(istat & (SIP|DIP)))
+		return;
+
+	np->profile.num_int++;
+
+	if (istat & CABRT)
+		OUTB (nc_istat, CABRT);
 
 	/*
 	**	Steinbach's Guideline for Systems Programming:
 	**	Never test for an error condition you don't know how to handle.
 	*/
 
-	dstat = (istat & DIP) ? INB (nc_dstat) : 0;
 	sist  = (istat & SIP) ? INW (nc_sist)  : 0;
-	np->profile.num_int++;
+	dstat = (istat & DIP) ? INB (nc_dstat) : 0;
 
 	if (DEBUG_FLAGS & DEBUG_TINY)
 		printf ("<%d|%x:%x|%x:%x>",
@@ -5469,297 +6791,121 @@
 			dstat,sist,
 			(unsigned)INL(nc_dsp),
 			(unsigned)INL(nc_dbc));
-	if ((dstat==DFE) && (sist==PAR)) return;
-
-/*==========================================================
-**
-**	First the normal cases.
-**
-**==========================================================
-*/
-	/*-------------------------------------------
-	**	SCSI reset
-	**-------------------------------------------
-	*/
-
-	if (sist & RST) {
-		ncr_init (np, bootverbose ? "scsi reset" : NULL, HS_RESET);
-		return;
-	};
 
-	/*-------------------------------------------
-	**	selection timeout
+	/*========================================================
+	**	First, interrupts we want to service cleanly.
 	**
-	**	IID excluded from dstat mask!
-	**	(chip bug)
-	**-------------------------------------------
-	*/
-
-	if ((sist  & STO) &&
-		!(sist  & (GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
-		!(dstat & (MDPE|BF|ABRT|SIR))) {
-		ncr_int_sto (np);
-		return;
-	};
-
-	/*-------------------------------------------
-	**      Phase mismatch.
-	**-------------------------------------------
-	*/
-
-	if ((sist  & MA) &&
-		!(sist  & (STO|GEN|HTH|SGE|UDC|RST|PAR)) &&
-		!(dstat & (MDPE|BF|ABRT|SIR|IID))) {
-		ncr_int_ma (np);
+	**	Phase mismatch is the most frequent interrupt, and 
+	**	so we have to service it as quickly and as cleanly 
+	**	as possible.
+	**	Programmed interrupts are rarely used in this driver,
+	**	but we must handle them cleanly anyway.
+	**	We try to deal with PAR and SBMC combined with 
+	**	some other interrupt(s).
+	**=========================================================
+	*/
+
+	if (!(sist  & (STO|GEN|HTH|SGE|UDC|RST)) &&
+	    !(dstat & (MDPE|BF|ABRT|IID))) {
+		if ((sist & SBMC) && ncr_int_sbmc (np))
+			return;
+		if ((sist & PAR)  && ncr_int_par  (np))
+			return;
+		if (sist & MA) {
+			ncr_int_ma (np);
+			return;
+		}
+		if (dstat & SIR) {
+			ncr_int_sir (np);
+			return;
+		}
+		if (!(sist & (SBMC|PAR)) && !(dstat & SSI))
+			printf("%s: unknown interrupt(s) ignored sist=%x dstat=%x\n",
+				ncr_name(np), sist, dstat);
+		OUTONB (nc_dcntl, (STD|NOCOM));
 		return;
 	};
 
-	/*----------------------------------------
-	**	move command with length 0
-	**----------------------------------------
+	/*========================================================
+	**	Now, interrupts that need some fixing up.
+	**	Order and multiple interrupts is so less important.
+	**
+	**	If SRST has been asserted, we just reset the chip.
+	**
+	**	Selection is intirely handled by the chip. If the 
+	**	chip says STO, we trust it. Seems some other 
+	**	interrupts may occur at the same time (UDC, IID), so 
+	**	we ignore them. In any case we do enough fix-up 
+	**	in the service routine.
+	**	We just exclude some fatal dma errors.
+	**=========================================================
 	*/
 
-	if ((dstat & IID) &&
-		!(sist  & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
-		!(dstat & (MDPE|BF|ABRT|SIR)) &&
-		((INL(nc_dbc) & 0xf8000000) == SCR_MOVE_TBL)) {
-		/*
-		**      Target wants more data than available.
-		**	The "no_data" script will do it.
-		*/
-		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, no_data));
+	if (sist & RST) {
+		ncr_init (np, bootverbose ? "scsi reset" : NULL, HS_RESET);
 		return;
 	};
 
-	/*-------------------------------------------
-	**	Programmed interrupt
-	**-------------------------------------------
-	*/
-
-	if ((dstat & SIR) &&
-		!(sist  & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
-		!(dstat & (MDPE|BF|ABRT|IID)) &&
-		(INB(nc_dsps) <= SIR_MAX)) {
-		ncr_int_sir (np);
+	if ((sist & STO) &&
+		!(dstat & (MDPE|BF|ABRT))) {
+		ncr_int_sto (np);
 		return;
 	};
 
-	/*========================================
-	**	do the register dump
-	**========================================
+	/*=========================================================
+	**	Now, interrupts we are not able to recover cleanly.
+	**	(At least for the moment).
+	**
+	**	Do the register dump.
+	**	Log message for real hard errors.
+	**	Clear all fifos.
+	**	For MDPE, BF, ABORT, IID, SGE and HTH we reset the 
+	**	BUS and the chip.
+	**	We are more soft for UDC.
+	**=========================================================
 	*/
 	if (jiffies - np->regtime > 10*HZ) {
-		int i;
 		np->regtime = jiffies;
-		for (i=0; i<sizeof(np->regdump); i++)
+		for (i = 0; i<sizeof(np->regdump); i++)
 			((char*)&np->regdump)[i] = INB_OFF(i);
 		np->regdump.nc_dstat = dstat;
 		np->regdump.nc_sist  = sist;
 	};
 
-	/*=========================================
-	**	log message for real hard errors
-	**=========================================
-
-	"ncr0 targ 0?: ERROR (ds:si) (so-si-sd) (sxfer/scntl3) @ (dsp:dbc)."
-	"	      reg: r0 r1 r2 r3 r4 r5 r6 ..... rf."
-
-	exception register:
-		ds:	dstat
-		si:	sist
-
-	SCSI bus lines:
-		so:	control lines as driver by NCR.
-		si:	control lines as seen by NCR.
-		sd:	scsi data lines as seen by NCR.
-
-	wide/fastmode:
-		sxfer:	(see the manual)
-		scntl3:	(see the manual)
-
-	current script command:
-		dsp:	script adress (relative to start of script).
-		dbc:	first word of script command.
-
-	First 16 register of the chip:
-		r0..rf
-
-	=============================================
-	*/
-
-	dsp = (unsigned) INL (nc_dsp);
-	dsa = (unsigned) INL (nc_dsa);
-
-	script_ofs = dsp - np->p_script;
-
-	printf ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ (%x:%08x).\n",
-		ncr_name (np), (unsigned)INB (nc_ctest0)&0x0f, dstat, sist,
-		(unsigned)INB (nc_socl), (unsigned)INB (nc_sbcl), (unsigned)INB (nc_sbdl),
-		(unsigned)INB (nc_sxfer),(unsigned)INB (nc_scntl3), script_ofs,
-		(unsigned) INL (nc_dbc));
-
-	if (((script_ofs & 3) == 0) &&
-	    (unsigned)script_ofs < sizeof(struct script)) {
-		printf ("\tscript cmd = %08x\n", 
-			(int) *(ncrcmd *)((char*)np->script +script_ofs));
-	}
-
-        printf ("\treg:\t");
-        for (i=0; i<16;i++)
-            printf (" %02x", (unsigned)INB_OFF(i));
-        printf (".\n");
-
-	/*----------------------------------------
-	**	clean up the dma fifo
-	**----------------------------------------
-	*/
-
-	if ( (INB(nc_sstat0) & (ILF|ORF|OLF)   ) ||
-	     (INB(nc_sstat1) & (FF3210)	) ||
-	     (INB(nc_sstat2) & (ILF1|ORF1|OLF1)) ||	/* wide .. */
-	     !(dstat & DFE)) {
-		printf ("%s: have to clear fifos.\n", ncr_name (np));
-		OUTB (nc_stest3, TE|CSF);	/* clear scsi fifo */
-		OUTB (nc_ctest3, CLF);		/* clear dma fifo  */
-	}
+	ncr_log_hard_error(np, sist, dstat);
 
-	/*----------------------------------------
-	**	handshake timeout
-	**----------------------------------------
-	*/
+	printf ("%s: have to clear fifos.\n", ncr_name (np));
+	OUTB (nc_stest3, TE|CSF);
+	OUTONB (nc_ctest3, CLF);
+
+	if ((sist & (SGE)) ||
+		(dstat & (MDPE|BF|ABORT|IID))) {
+		ncr_start_reset(np, 2);
+		return;
+	};
 
 	if (sist & HTH) {
 		printf ("%s: handshake timeout\n", ncr_name(np));
-		OUTB (nc_scntl1, CRST);
-		DELAY (1000);
-		OUTB (nc_scntl1, 0x00);
-		OUTB (nc_scr0, HS_FAIL);
-		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
-		return;
-	}
-
-	/*----------------------------------------
-	**	unexpected disconnect
-	**----------------------------------------
-	*/
-
-	if ((sist  & UDC) &&
-		!(sist  & (STO|GEN|HTH|MA|SGE|RST|PAR)) &&
-		!(dstat & (MDPE|BF|ABRT|SIR|IID))) {
-		OUTB (nc_scr0, HS_UNEXPECTED);
-		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
+		ncr_start_reset(np, 2);
 		return;
 	};
 
-	/*----------------------------------------
-	**	cannot disconnect
-	**----------------------------------------
-	*/
-
-	if ((dstat & IID) &&
-		!(sist  & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
-		!(dstat & (MDPE|BF|ABRT|SIR)) &&
-		((INL(nc_dbc) & 0xf8000000) == SCR_WAIT_DISC)) {
-		/*
-		**      Unexpected data cycle while waiting for disconnect.
-		*/
-		if (INB(nc_sstat2) & LDSC) {
-			/*
-			**	It's an early reconnect.
-			**	Let's continue ...
-			*/
-			OUTB (nc_dcntl, (STD|NOCOM));
-			/*
-			**	info message
-			*/
-			printf ("%s: INFO: LDSC while IID.\n",
-				ncr_name (np));
-			return;
+	if (sist & UDC) {
+		printf ("%s: unexpected disconnect\n", ncr_name(np));
+		if (INB (nc_scr1) != 0xff) {
+			OUTB (nc_scr1, HS_UNEXPECTED);
+			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
 		};
-		printf ("%s: target %d doesn't release the bus.\n",
-			ncr_name (np), (int)INB (nc_ctest0)&0x0f);
-		/*
-		**	return without restarting the NCR.
-		**	timeout will do the real work.
-		*/
-		return;
-	};
-
-	/*----------------------------------------
-	**	single step
-	**----------------------------------------
-	*/
-
-	if ((dstat & SSI) &&
-		!(sist  & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) &&
-		!(dstat & (MDPE|BF|ABRT|SIR|IID))) {
-		OUTB (nc_dcntl, (STD|NOCOM));
-		return;
-	};
-
-/*
-**	@RECOVER@ HTH, SGE, ABRT.
-**
-**	We should try to recover from these interrupts.
-**	They may occur if there are problems with synch transfers, or 
-**	if targets are switched on or off while the driver is running.
-*/
-
-	if (sist & SGE) {
-		OUTB (nc_ctest3, CLF);		/* clear scsi offsets */
-	}
-
-	/*
-	**	Freeze controller to be able to read the messages.
-	*/
-
-	if (DEBUG_FLAGS & DEBUG_FREEZE) {
-		unsigned char val;
-		for (i=0; i<0x60; i++) {
-			switch (i%16) {
-
-			case 0:
-				printf ("%s: reg[%d0]: ",
-					ncr_name(np),i/16);
-				break;
-			case 4:
-			case 8:
-			case 12:
-				printf (" ");
-				break;
-			};
-			val = INB_OFF(i);
-			printf (" %x%x", val/16, val%16);
-			if (i%16==15) printf (".\n");
-		}
-
-		del_timer(&np->timer);
-
-		printf ("%s: halted!\n", ncr_name(np));
-		/*
-		**	don't restart controller ...
-		*/
-		OUTB (nc_istat,  SRST);
+		ncr_start_reset(np, 2);
 		return;
 	};
 
-#ifdef NCR_FREEZE
-	/*
-	**	Freeze system to be able to read the messages.
-	*/
-	printf ("ncr: fatal error: system halted - press reset to reboot ...");
-	cli();
-	for (;;);
-#endif
-
-	/*
-	**	sorry, have to kill ALL jobs ...
+	/*=========================================================
+	**	We just miss the cause of the interrupt. :(
+	**	Print a message. The timeout will do the real work.
+	**=========================================================
 	*/
-
-	ncr_init (np, "fatal error", HS_FAIL);
-#ifndef SCSI_NCR_NO_DISCONNECT
-	np->disc = 1;
-#endif
+	printf ("%s: unknown interrupt\n", ncr_name(np));
 }
 
 /*==========================================================
@@ -5789,7 +6935,7 @@
 	*/
 
 	dsa = INL (nc_dsa);
-	cp = &np->ccb;
+	cp = np->ccb;
 	while (cp && (CCB_PHYS (cp, phys) != dsa))
 		cp = cp->link_ccb;
 
@@ -5803,7 +6949,7 @@
 	*/
 
 	scratcha = INL (nc_scratcha);
-	diff = scratcha - NCB_SCRIPT_PHYS (np, tryloop);
+	diff = scratcha - NCB_SCRIPTH_PHYS (np, tryloop);
 
 /*	assert ((diff <= MAX_START * 20) && !(diff % 20));*/
 
@@ -5813,9 +6959,55 @@
 		return;
 	};
 	ncr_init (np, "selection timeout", HS_FAIL);
-#ifndef SCSI_NCR_NO_DISCONNECT
 	np->disc = 1;
-#endif
+}
+
+/*==========================================================
+**
+**	ncr chip exception handler for SCSI bus mode change
+**
+**==========================================================
+**
+**	spi2-r12 11.2.3 says a transceiver mode change must 
+**	generate a reset event and a device that detects a reset 
+**	event shall initiate a hard reset. It says also that a
+**	device that detects a mode change shall set data transfer 
+**	mode to eight bit asynchronous, etc...
+**	So, just resetting should be enough.
+**	 
+**
+**----------------------------------------------------------
+*/
+
+static int ncr_int_sbmc (ncb_p np)
+{
+	u_char scsi_mode = INB (nc_stest4) & SMODE;
+
+	printf("%s: SCSI bus mode change from %x to %x, resetting ...\n",
+		ncr_name(np), np->scsi_mode, scsi_mode);
+
+	np->scsi_mode = scsi_mode;
+	ncr_start_reset(np, 2);
+
+	return 1;
+}
+
+/*==========================================================
+**
+**	ncr chip exception handler for SCSI parity error.
+**
+**==========================================================
+**
+**	SCSI parity errors are handled by the SCSI script.
+**	So, we just print some message.
+**
+**----------------------------------------------------------
+*/
+
+static int ncr_int_par (ncb_p np)
+{
+	printf("%s: SCSI parity error detected\n", ncr_name(np));
+	return 0;
 }
 
 /*==========================================================
@@ -5836,49 +7028,76 @@
 {
 	u_int32	dbc;
 	u_int32	rest;
-	u_int32	dsa;
 	u_int32	dsp;
+	u_int32	dsa;
 	u_int32	nxtdsp;
 	u_int32	*vdsp;
 	u_int32	oadr, olen;
 	u_int32	*tblp;
         ncrcmd *newcmd;
-	u_char	cmd, sbcl, delta, ss0, ss2;
+	u_char	cmd, sbcl;
 	ccb_p	cp;
 
-	dsp = INL (nc_dsp);
-	dsa = INL (nc_dsa);
-	dbc = INL (nc_dbc);
-	ss0 = INB (nc_sstat0);
-	ss2 = INB (nc_sstat2);
-	sbcl= INB (nc_sbcl);
-
-	cmd = dbc >> 24;
-	rest= dbc & 0xffffff;
-	delta=(INB (nc_dfifo) - rest) & 0x7f;
-
-	/*
-	**	The data in the dma fifo has not been transfered to
-	**	the target -> add the amount to the rest
-	**	and clear the data.
-	**	Check the sstat2 register in case of wide transfer.
-	*/
-
-	if (! (INB(nc_dstat) & DFE)) rest += delta;
-	if (ss0 & OLF) rest++;
-	if (ss0 & ORF) rest++;
-	if (INB(nc_scntl3) & EWS) {
-		if (ss2 & OLF1) rest++;
-		if (ss2 & ORF1) rest++;
-	};
-	OUTB (nc_ctest3, CLF   );	/* clear dma fifo  */
-	OUTB (nc_stest3, TE|CSF);	/* clear scsi fifo */
+	dsp	= INL (nc_dsp);
+	dbc	= INL (nc_dbc);
+	sbcl	= INB (nc_sbcl);
+
+	cmd	= dbc >> 24;
+	rest	= dbc & 0xffffff;
+
+	/*
+	**	Take into account dma fifo and various buffers and latches,
+	**	only if the interrupted phase is an OUTPUT phase.
+	*/
+
+	if ((cmd & 1) == 0) {
+		u_char	ctest5, ss0, ss2;
+		u_short	delta;
+
+		ctest5 = (np->rv_ctest5 & DFS) ? INB (nc_ctest5) : 0;
+		if (ctest5 & DFS)
+			delta=(((ctest5 << 8) | (INB (nc_dfifo) & 0xff)) - rest) & 0x3ff;
+		else
+			delta=(INB (nc_dfifo) - rest) & 0x7f;
+
+		/*
+		**	The data in the dma fifo has not been transfered to
+		**	the target -> add the amount to the rest
+		**	and clear the data.
+		**	Check the sstat2 register in case of wide transfer.
+		*/
+
+		rest += delta;
+		ss0  = INB (nc_sstat0);
+		if (ss0 & OLF) rest++;
+		if (ss0 & ORF) rest++;
+		if (INB(nc_scntl3) & EWS) {
+			ss2 = INB (nc_sstat2);
+			if (ss2 & OLF1) rest++;
+			if (ss2 & ORF1) rest++;
+		};
+
+		OUTONB (nc_ctest3, CLF );	/* clear dma fifo  */
+		OUTB (nc_stest3, TE|CSF);	/* clear scsi fifo */
+
+		if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE))
+			printf ("P%x%x RL=%d D=%d SS0=%x ", cmd&7, sbcl&7,
+				(unsigned) rest, (unsigned) delta, ss0);
+
+	} else	{
+		if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE))
+			printf ("P%x%x RL=%d ", cmd&7, sbcl&7, rest);
+		if ((cmd & 7) != 1) {
+			OUTONB (nc_ctest3, CLF );
+			OUTB (nc_stest3, TE|CSF);
+		}
+	}
 
 	/*
 	**	locate matching cp
 	*/
 	dsa = INL (nc_dsa);
-	cp = &np->ccb;
+	cp  = np->ccb;
 	while (cp && (CCB_PHYS (cp, phys) != dsa))
 		cp = cp->link_ccb;
 
@@ -5904,19 +7123,18 @@
 	} else if (dsp == vtophys (&cp->patch[6])) {
 		vdsp = &cp->patch[4];
 		nxtdsp = vdsp[3];
-	} else {
+	} else if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) {
 		vdsp = (u_int32 *) ((char*)np->script - np->p_script + dsp -8);
 		nxtdsp = dsp;
+	} else {
+		vdsp = (u_int32 *) ((char*)np->scripth - np->p_scripth + dsp -8);
+		nxtdsp = dsp;
 	};
 
 	/*
 	**	log the information
 	*/
-	if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE)) {
-		printf ("P%x%x ",cmd&7, sbcl&7);
-		printf ("RL=%d D=%d SS0=%x ",
-			(unsigned) rest, (unsigned) delta, ss0);
-	};
+
 	if (DEBUG_FLAGS & DEBUG_PHASE) {
 		printf ("\nCP=%p CP2=%p DSP=%x NXT=%x VDSP=%p CMD=%x ",
 			cp, np->header.cp,
@@ -5948,7 +7166,7 @@
 	};
 
 	/*
-	**	if old phase not dataphase, leave here.
+	**	check cmd against assumed interrupted script command.
 	*/
 
 	if (cmd != (vdsp[0] >> 24)) {
@@ -5958,13 +7176,25 @@
 		
 		return;
 	}
+
+#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
+	if ((cmd & 7) == 1 && np->assert_atn) {
+		np->assert_atn = 0;
+		OUTONB(nc_socl, CATN);
+	}
+#endif
+
+	/*
+	**	if old phase not dataphase, leave here.
+	*/
+
 	if (cmd & 0x06) {
 		PRINT_ADDR(cp->cmd);
 		printf ("phase change %x-%x %d@%08x resid=%d.\n",
 			cmd&7, sbcl&7, (unsigned)olen,
 			(unsigned)oadr, (unsigned)rest);
 
-		OUTB (nc_dcntl, (STD|NOCOM));
+		OUTONB (nc_dcntl, (STD|NOCOM));
 		return;
 	};
 
@@ -6000,7 +7230,10 @@
 	*/
 	np->profile.num_break++;
 	OUTL (nc_temp, vtophys (newcmd));
-	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
+	if ((cmd & 7) == 0)
+		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
+	else
+		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, checkatn));
 }
 
 /*==========================================================
@@ -6031,11 +7264,12 @@
 
 void ncr_int_sir (ncb_p np)
 {
+	u_char scntl3;
 	u_char chg, ofs, per, fak, wide;
 	u_char num = INB (nc_dsps);
 	ccb_p	cp=0;
 	u_long	dsa;
-	u_char	target = INB (nc_ctest0) & 7;
+	u_char	target = INB (nc_ctest0) & 0x0f;
 	tcb_p	tp     = &np->target[target];
 	int     i;
 	if (DEBUG_FLAGS & DEBUG_TINY) printf ("I#%d", num);
@@ -6044,13 +7278,15 @@
 	case SIR_SENSE_RESTART:
 	case SIR_STALL_RESTART:
 		break;
+	case SIR_STALL_QUEUE:	/* Ignore, just restart the script */
+		goto out;
 
 	default:
 		/*
 		**	lookup the ccb
 		*/
 		dsa = INL (nc_dsa);
-		cp = &np->ccb;
+		cp = np->ccb;
 		while (cp && (CCB_PHYS (cp, phys) != dsa))
 			cp = cp->link_ccb;
 
@@ -6063,6 +7299,32 @@
 	}
 
 	switch (num) {
+		u_long endp;
+	case SIR_DATA_IO_IS_OUT:
+	case SIR_DATA_IO_IS_IN:
+/*
+**	We did not guess the direction of transfer. We have to wait for 
+**	actual data direction driven by the target before setting 
+**	pointers. We must patch the global header too.
+*/
+		if (num == SIR_DATA_IO_IS_OUT) {
+			endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16;
+			cp->phys.header.goalp = endp + 8;
+			cp->phys.header.savep = endp - cp->segments*16;
+		} else {
+			endp = NCB_SCRIPT_PHYS (np, data_in)  + MAX_SCATTER*16;
+			cp->phys.header.goalp = endp + 8;
+			cp->phys.header.savep = endp - cp->segments*16;
+		}
+
+		cp->phys.header.lastp	= cp->phys.header.savep;
+		np->header.savep	= cp->phys.header.savep;
+		np->header.goalp	= cp->phys.header.goalp;
+		np->header.lastp	= cp->phys.header.lastp;
+		OUTL (nc_temp,	np->header.savep);
+		OUTL (nc_dsp,	np->header.savep);
+		return;
+		/* break; */
 
 /*--------------------------------------------------------------------
 **
@@ -6099,7 +7361,7 @@
 			if (DEBUG_FLAGS & DEBUG_RESTART)
 				printf ("+ restart job ..\n");
 			OUTL (nc_dsa, CCB_PHYS (cp, phys));
-			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, getcc));
+			OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, getcc));
 			return;
 		};
 
@@ -6230,11 +7492,11 @@
 		switch (cp->nego_status) {
 
 		case NS_SYNC:
-			ncr_setsync (np, cp, 0xe0);
+			ncr_setsync (np, cp, 0, 0xe0);
 			break;
 
 		case NS_WIDE:
-			ncr_setwide (np, cp, 0);
+			ncr_setwide (np, cp, 0, 0);
 			break;
 
 		};
@@ -6277,8 +7539,8 @@
 		**	check values against driver limits.
 		*/
 
-		if (per < np->ns_sync)
-			{chg = 1; per = np->ns_sync;}
+		if (per < np->minsync)
+			{chg = 1; per = np->minsync;}
 		if (per < tp->minsync)
 			{chg = 1; per = tp->minsync;}
 		if (ofs > tp->maxoffs)
@@ -6287,23 +7549,26 @@
 		/*
 		**	Check against controller limits.
 		*/
+		fak	= 7;
+		scntl3	= 0;
 		if (ofs != 0) {
-			fak = (4ul * per - 1) / np->ns_sync - 3;
-			if (fak>7) {
+			ncr_getsync(np, per, &fak, &scntl3);
+			if (fak > 7) {
 				chg = 1;
 				ofs = 0;
 			}
 		}
 		if (ofs == 0) {
-			fak = 7;
-			per = 0;
+			fak	= 7;
+			per	= 0;
+			scntl3	= 0;
 			tp->minsync = 0;
 		}
 
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
 			PRINT_ADDR(cp->cmd);
-			printf ("sync: per=%d ofs=%d fak=%d chg=%d.\n",
-				per, ofs, fak, chg);
+			printf ("sync: per=%d scntl3=0x%x ofs=%d fak=%d chg=%d.\n",
+				per, scntl3, ofs, fak, chg);
 		}
 
 		if (INB (HS_PRT) == HS_NEGOTIATE) {
@@ -6318,19 +7583,19 @@
 					/*
 					**	Answer wasn't acceptable.
 					*/
-					ncr_setsync (np, cp, 0xe0);
+					ncr_setsync (np, cp, 0, 0xe0);
 					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
 				} else {
 					/*
 					**	Answer is ok.
 					*/
-					ncr_setsync (np, cp, (fak<<5)|ofs);
+					ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
 					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
 				};
 				return;
 
 			case NS_WIDE:
-				ncr_setwide (np, cp, 0);
+				ncr_setwide (np, cp, 0, 0);
 				break;
 			};
 		};
@@ -6354,7 +7619,7 @@
 		**      prepare an answer message
 		*/
 
-		ncr_setsync (np, cp, (fak<<5)|ofs);
+		ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
 
 		np->msgout[0] = M_EXTENDED;
 		np->msgout[1] = 3;
@@ -6367,7 +7632,7 @@
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
 			PRINT_ADDR(cp->cmd);
 			printf ("sync msgout: ");
-			(void) ncr_show_msg (np->msgin);
+			(void) ncr_show_msg (np->msgout);
 			printf (".\n");
 		}
 
@@ -6429,19 +7694,19 @@
 					/*
 					**	Answer wasn't acceptable.
 					*/
-					ncr_setwide (np, cp, 0);
+					ncr_setwide (np, cp, 0, 1);
 					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
 				} else {
 					/*
 					**	Answer is ok.
 					*/
-					ncr_setwide (np, cp, wide);
+					ncr_setwide (np, cp, wide, 1);
 					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
 				};
 				return;
 
 			case NS_SYNC:
-				ncr_setsync (np, cp, 0xe0);
+				ncr_setsync (np, cp, 0, 0xe0);
 				break;
 			};
 		};
@@ -6451,7 +7716,7 @@
 		**      prepare an answer message
 		*/
 
-		ncr_setwide (np, cp, wide);
+		ncr_setwide (np, cp, wide, 1);
 
 		np->msgout[0] = M_EXTENDED;
 		np->msgout[1] = 2;
@@ -6534,13 +7799,14 @@
 		*/
 
 		PRINT_ADDR(cp->cmd);
-		printf ("M_DISCONNECT received, but datapointer not saved:\n"
-			"\tdata=%x save=%x goal=%x.\n",
+		printf ("M_DISCONNECT received, but datapointer not saved: "
+			"data=%x save=%x goal=%x.\n",
 			(unsigned) INL (nc_temp),
 			(unsigned) np->header.savep,
 			(unsigned) np->header.goalp);
 		break;
 
+#if 0   /* This stuff does not work */
 /*--------------------------------------------------------------------
 **
 **	Processing of a "S_QUEUE_FULL" status.
@@ -6571,14 +7837,9 @@
 		np->script->start1[0] =  SCR_INT;
 
 		/*
-		**	For the moment tagged transfers cannot be disabled.
-		*/
-#if 0
-		/*
 		**	Try to disable tagged transfers.
 		*/
 		ncr_setmaxtags (np, &np->target[target], 0);
-#endif
 
 		/*
 		** @QUEUE@
@@ -6601,7 +7862,7 @@
 		/*
 		**	Look for a disconnected job.
 		*/
-		cp = &np->ccb;
+		cp = np->ccb;
 		while (cp && cp->host_status != HS_DISCONNECT)
 			cp = cp->link_ccb;
 
@@ -6623,10 +7884,11 @@
 		printf ("%s: queue empty.\n", ncr_name (np));
 		np->script->start1[0] =  SCR_INT ^ IFFALSE (0);
 		break;
+#endif   /* This stuff does not work */
 	};
 
 out:
-	OUTB (nc_dcntl, (STD|NOCOM));
+	OUTONB (nc_dcntl, (STD|NOCOM));
 }
 
 /*==========================================================
@@ -6649,7 +7911,9 @@
 	*/
 
 	lp = np->target[target].lp[lun];
-	if (lp) {
+
+	if (lp && lp->opennings && (!lp->active || lp->active < lp->reqlink)) {
+
 		cp = lp->next_ccb;
 
 		/*
@@ -6657,6 +7921,15 @@
 		*/
 
 		while (cp && cp->magic) cp = cp->next_ccb;
+
+		/*
+		**	Increment active commands and decrement credit.
+		*/
+
+		if (cp) {
+			++lp->active;
+			--lp->opennings;
+		}
 	}
 
 	/*
@@ -6668,7 +7941,7 @@
 	if ((!cp) && lp && lp->actccbs > 0)
 		return ((ccb_p) 0);
 
-	if (!cp) cp = &np->ccb;
+	if (!cp) cp = np->ccb;
 
 	/*
 	**	Wait until available.
@@ -6697,18 +7970,30 @@
 **==========================================================
 */
 
-void ncr_free_ccb (ncb_p np, ccb_p cp)
+void ncr_free_ccb (ncb_p np, ccb_p cp, u_long target, u_long lun)
 {
+	lcb_p lp;
+
 	/*
 	**    sanity
 	*/
 
 	assert (cp != NULL);
 
+	/*
+	**	Decrement active commands and increment credit.
+	*/
+
+	lp = np->target[target].lp[lun];
+	if (lp) {
+			--lp->active;
+			++lp->opennings;
+	}
+
 	cp -> host_status = HS_IDLE;
 	cp -> magic = 0;
 #if 0
-	if (cp == &np->ccb)
+	if (cp == np->ccb)
 		wakeup ((caddr_t) cp);
 #endif
 }
@@ -6743,10 +8028,12 @@
 		tp->jump_tcb.l_cmd   = (SCR_JUMP^IFFALSE (DATA (0x80 + target)));
 		tp->jump_tcb.l_paddr = np->jump_tcb.l_paddr;
 
-		tp->getscr[0] = SCR_COPY (1);
+		tp->getscr[0] =
+			(np->features & FE_PFEN)? SCR_COPY(1) : SCR_COPY_F(1);
 		tp->getscr[1] = vtophys (&tp->sval);
 		tp->getscr[2] = np->paddr + offsetof (struct ncr_reg, nc_sxfer);
-		tp->getscr[3] = SCR_COPY (1);
+		tp->getscr[3] =
+			(np->features & FE_PFEN)? SCR_COPY(1) : SCR_COPY_F(1);
 		tp->getscr[4] = vtophys (&tp->wval);
 		tp->getscr[5] = np->paddr + offsetof (struct ncr_reg, nc_scntl3);
 
@@ -6759,7 +8046,7 @@
 		tp->call_lun.l_paddr = NCB_SCRIPT_PHYS (np, resel_lun);
 
 		tp->jump_lcb.l_cmd   = (SCR_JUMP);
-		tp->jump_lcb.l_paddr = NCB_SCRIPT_PHYS (np, abort);
+		tp->jump_lcb.l_paddr = NCB_SCRIPTH_PHYS (np, abort);
 		np->jump_tcb.l_paddr = vtophys (&tp->jump_tcb);
 	}
 
@@ -6771,7 +8058,7 @@
 		/*
 		**	Allocate a lcb
 		*/
-		lp = (lcb_p) m_alloc (sizeof (struct lcb));
+		lp = (lcb_p) m_alloc (sizeof (struct lcb), LCB_ALIGN_SHIFT);
 		if (!lp) return;
 
 		if (DEBUG_FLAGS & DEBUG_ALLOC) {
@@ -6790,31 +8077,25 @@
 		lp->call_tag.l_paddr = NCB_SCRIPT_PHYS (np, resel_tag);
 
 		lp->jump_ccb.l_cmd   = (SCR_JUMP);
-		lp->jump_ccb.l_paddr = NCB_SCRIPT_PHYS (np, aborttag);
+		lp->jump_ccb.l_paddr = NCB_SCRIPTH_PHYS (np, aborttag);
 
 		lp->actlink = 1;
 
+		lp->active  = 1;
+
 		/*
 		**   Chain into LUN list
 		*/
 		tp->jump_lcb.l_paddr = vtophys (&lp->jump_lcb);
 		tp->lp[lun] = lp;
 
-#ifndef SCSI_NCR_TAGGED_QUEUE_DISABLED
-		if (!lp->usetags) {
-			ncr_setmaxtags (np, tp, SCSI_NCR_MAX_TAGS);
-		}
-#endif
+		ncr_setmaxtags (np, tp, driver_setup.default_tags);
 	}
 
 	/*
 	**	Allocate ccbs up to lp->reqccbs.
-	**
-	**	This modification will be reworked in a future release.
 	*/
 
-loop_alloc_ccb:
-
 	/*
 	**	Limit possible number of ccbs.
 	**
@@ -6828,7 +8109,7 @@
 	/*
 	**	Allocate a ccb
 	*/
-	cp = (ccb_p) m_alloc (sizeof (struct ccb));
+	cp = (ccb_p) m_alloc (sizeof (struct ccb), CCB_ALIGN_SHIFT);
 	if (!cp)
 		return;
 
@@ -6866,16 +8147,68 @@
 	/*
 	**	Chain into wakeup list
 	*/
-	cp->link_ccb      = np->ccb.link_ccb;
-	np->ccb.link_ccb  = cp;
+	cp->link_ccb      = np->ccb->link_ccb;
+	np->ccb->link_ccb = cp;
 
 	/*
 	**	Chain into CCB list
 	*/
-	cp->next_ccb	= lp->next_ccb;
-	lp->next_ccb	= cp;
+	cp->next_ccb	= lp->next_ccb;
+	lp->next_ccb	= cp;
+}
+
+/*==========================================================
+**
+**
+**	Announce the number of ccbs/tags to the scsi driver.
+**
+**
+**==========================================================
+*/
+
+static void ncr_opennings (ncb_p np, lcb_p lp, Scsi_Cmnd * cmd)
+{
+	/*
+	**	want to reduce the number ...
+	*/
+	if (lp->actlink > lp->reqlink) {
+
+		/*
+		**	Try to  reduce the count.
+		**	We assume to run at splbio ..
+		*/
+		u_char diff = lp->actlink - lp->reqlink;
+
+		if (!diff) return;
+
+		if (diff > lp->opennings)
+			diff = lp->opennings;
+
+		lp->opennings	-= diff;
+
+		lp->actlink	-= diff;
+		if (DEBUG_FLAGS & DEBUG_TAGS)
+			printf ("%s: actlink: diff=%d, new=%d, req=%d\n",
+				ncr_name(np), diff, lp->actlink, lp->reqlink);
+		return;
+	};
+
+	/*
+	**	want to increase the number ?
+	*/
+	if (lp->reqlink > lp->actlink) {
+		u_char diff = lp->reqlink - lp->actlink;
 
-goto loop_alloc_ccb;
+		lp->opennings	+= diff;
+
+		lp->actlink	+= diff;
+#if 0
+		wakeup ((caddr_t) xp->sc_link);
+#endif
+		if (DEBUG_FLAGS & DEBUG_TAGS)
+			printf ("%s: actlink: diff=%d, new=%d, req=%d\n",
+				ncr_name(np), diff, lp->actlink, lp->reqlink);
+	};
 }
 
 /*==========================================================
@@ -6894,8 +8227,7 @@
 **----------------------------------------------------------
 */
 
-/*	FreeBSD driver important comments
-**	---------------------------------
+/*
 **	We try to reduce the number of interrupts caused
 **	by unexpected phase changes due to disconnects.
 **	A typical harddisk may disconnect before ANY block.
@@ -6903,158 +8235,49 @@
 **	we had to use a break point every 512 bytes.
 **	Of course the number of scatter/gather blocks is
 **	limited.
+**	Under Linux, the scatter/gatter blocks are provided by 
+**	the generic driver. We just have to copy addresses and 
+**	sizes to the data segment array.
 */
 
-/*
-**	The scatterlist passed by the linux middle-level scsi drivers
-**	may contain blocks of any size (Generaly < 1024 bytes blocks,
-**	can be 4096 with a 4K fs).
-*/
-
-#if defined(SCSI_NCR_SEGMENT_SIZE)
 static	int	ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd)
 {
-	struct scatterlist *scatter;
-	struct dsb *phys;
-	register u_short segment = 0;
-	register u_short o_segment = 0;
-	u_short chunk, chunk_min;
-	u_long segaddr;
-	int segsize;
-	int datalen;
-
-	phys = &cp->phys;
-	cp->data_len = 0;
-
-	/*
-	**	Compute a good value for chunk size
-	**	If SCSI_NCR_SEGMENT_SIZE is OK, we will try to use it. 
-	*/
-
-	if (!cmd->use_sg)
-		cp->data_len	= cmd->request_bufflen;
-	else {
-		scatter = (struct scatterlist *)cmd->buffer;
-		for (segment = 0 ; segment < cmd->use_sg ; segment++)
-			cp->data_len += scatter[segment].length;
-	}
-
-
-	if (!cp->data_len) {
-		bzero (&phys->data, sizeof (phys->data));
-		return 0;
-	}
-
-	chunk_min	= cp->data_len / MAX_SCATTER;
-	for (chunk = SCSI_NCR_SEGMENT_SIZE ; chunk < chunk_min ; chunk += chunk);
-
-	/*
-	**	If the linux scsi command is not a scatterlist,
-	**	the computed chunk size is OK.
-	*/
-
-	if (!cmd->use_sg) {
-		bzero (&phys->data, sizeof (phys->data));
-		datalen = cmd->request_bufflen;
-		segaddr = vtophys(cmd->request_buffer);
-		segsize = chunk;
-		o_segment = 0;
-
-if (DEBUG_FLAGS & DEBUG_SCATTER)
-	printf("ncr53c8xx: re-scattering physical=0x%x size=%d chunk=%d.\n",
-	(unsigned) segaddr, (int) datalen, (int) chunk);
-
-		while (datalen && (o_segment < MAX_SCATTER)) {
-			if (segsize > datalen) segsize	= datalen;
-			phys->data[o_segment].addr	= segaddr;
-			phys->data[o_segment].size	= segsize;
+	struct scr_tblmove *data;
+	int segment	= 0;
+	int use_sg	= (int) cmd->use_sg;
 
-			datalen -= segsize;
-
-if(DEBUG_FLAGS & DEBUG_SCATTER)
-	printf ("ncr53c8xx:     seg #%d  addr=%lx  size=%d  (rest=%d).\n",
-	o_segment, segaddr, (int) segsize, (int) datalen);
+#if 0
+	bzero (cp->phys.data, sizeof (cp->phys.data));
+#endif
+	data		= cp->phys.data;
+	cp->data_len	= 0;
 
-			segaddr	+= segsize;
-			o_segment++;
+	if (!use_sg) {
+		if (cmd->request_bufflen) {
+			data = &data[MAX_SCATTER - 1];
+			data[0].addr	= vtophys(cmd->request_buffer);
+			data[0].size	= cmd->request_bufflen;
+			cp->data_len	= data[0].size;
+			segment = 1;
 		}
-
-		return datalen ? -1 : o_segment;
 	}
+	else if (use_sg <= MAX_SCATTER) {
+		struct scatterlist *scatter = (struct scatterlist *)cmd->buffer;
 
-	/*
-	**	Else, the computed chunk size is not so good
-	**	and we have to iterate.
-	**	Rescatter the Linux scatterlist into the data block descriptor.
-	**	Loop if necessary, beginning with the not so good chunk size and
-	**	doubling it if the scatter process fails.
-	*/
-
-	scatter = (struct scatterlist *)cmd->buffer;
-	for (segment = 0; segment < cmd->use_sg; chunk += chunk) {
-		o_segment	= 0;
-		bzero (&phys->data, sizeof (phys->data));
-		for (segment = 0 ; segment < cmd->use_sg ; segment++) {
-			datalen = scatter[segment].length;
-			segaddr = vtophys(scatter[segment].address);
-			segsize = chunk;
-
-if (DEBUG_FLAGS & DEBUG_SCATTER)
-	printf("ncr53c8xx: re-scattering physical=0x%x size=%d chunk=%d.\n",
-	(unsigned) segaddr, (int) datalen, (int) chunk);
-
-			while (datalen && (o_segment < MAX_SCATTER)) {
-				if (segsize > datalen) segsize	= datalen;
-				phys->data[o_segment].addr	= segaddr;
-				phys->data[o_segment].size	= segsize;
-
-				datalen -= segsize;
-
-if(DEBUG_FLAGS & DEBUG_SCATTER)
-	printf ("ncr53c8xx:     seg #%d  addr=%lx  size=%d  (rest=%d).\n",
-	o_segment, segaddr, (int) segsize, (int) datalen);
-
-				segaddr	+= segsize;
-				o_segment++;
-			}
-
-			if (datalen) break;
+		data = &data[MAX_SCATTER - use_sg];
+		while (segment < use_sg) {
+			data[segment].addr = vtophys(scatter[segment].address);
+			data[segment].size = scatter[segment].length;
+			cp->data_len	   += data[segment].size;
+			++segment;
 		}
 	}
-
-	return segment < cmd->use_sg ? -1 : o_segment;
-}
-
-#else /* !defined SCSI_NCR_SEGMENT_SIZE */
-
-static	int	ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd)
-{
-	struct dsb *phys = &cp->phys;
-	u_short	segment  = 0;
-
-	cp->data_len = 0;
-	bzero (&phys->data, sizeof (phys->data));
-
-	if (!cmd->use_sg) {
-	     phys->data[segment].addr = vtophys(cmd->request_buffer);
-	     phys->data[segment].size = cmd->request_bufflen;
-	     cp->data_len            += phys->data[segment].size;
-	     segment++;
-	     return segment;
-	}
-
-	while (segment < cmd->use_sg && segment < MAX_SCATTER) {
-	     struct scatterlist *scatter = (struct scatterlist *)cmd->buffer;
-
-	     phys->data[segment].addr = vtophys(scatter[segment].address);
-	     phys->data[segment].size = scatter[segment].length;
-	     cp->data_len            += phys->data[segment].size;
-	     ++segment;
+	else {
+		return -1;
 	}
 
-	return segment < cmd->use_sg ? -1 : segment;
+	return segment;
 }
-#endif /* SCSI_NCR_SEGMENT_SIZE */
 
 /*==========================================================
 **
@@ -7068,7 +8291,9 @@
 */
 
 #ifndef NCR_IOMAPPED
+__initfunc(
 static int ncr_regtest (struct ncb* np)
+)
 {
 	register volatile u_long data;
 	/*
@@ -7092,12 +8317,14 @@
 }
 #endif
 
+__initfunc(
 static int ncr_snooptest (struct ncb* np)
+)
 {
 	u_long	ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc, err=0;
 	int	i;
 #ifndef NCR_IOMAPPED
-	if (np->use_mmio) {
+	if (np->reg) {
             err |= ncr_regtest (np);
             if (err) return (err);
 	}
@@ -7105,7 +8332,7 @@
 	/*
 	**	init
 	*/
-	pc  = NCB_SCRIPT_PHYS (np, snooptest);
+	pc  = NCB_SCRIPTH_PHYS (np, snooptest);
 	host_wr = 1;
 	ncr_wr  = 2;
 	/*
@@ -7149,8 +8376,11 @@
 	/*
 	**	Check termination position.
 	*/
-	if (pc != NCB_SCRIPT_PHYS (np, snoopend)+8) {
+	if (pc != NCB_SCRIPTH_PHYS (np, snoopend)+8) {
 		printf ("CACHE TEST FAILED: script execution failed.\n");
+		printf ("start=%08lx, pc=%08lx, end=%08lx\n", 
+			(u_long) NCB_SCRIPTH_PHYS (np, snooptest), pc,
+			(u_long) NCB_SCRIPTH_PHYS (np, snoopend) +8);
 		return (0x40);
 	};
 	/*
@@ -7183,23 +8413,19 @@
 **==========================================================
 */
 
-/*
-**	Compute the difference in milliseconds.
-**/
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 
-#ifdef SCSI_NCR_PROFILE
+/*
+**	Compute the difference in jiffies ticks.
+*/
 
-static	int ncr_delta (u_long from, u_long to)
-{
-	if (!from) return (-1);
-	if (!to) return (-2);
-	return ((to  - from) * 1000 / HZ );
-}
+#define ncr_delta(from, to) \
+	( ((to) && (from))? (to) - (from) : -1 )
 
 #define PROFILE  cp->phys.header.stamp
 static	void ncb_profile (ncb_p np, ccb_p cp)
 {
-	int co, da, st, en, di, se, post,work,disc;
+	int co, st, en, di, se, post,work,disc;
 	u_long diff;
 
 	PROFILE.end = jiffies;
@@ -7207,9 +8433,6 @@
 	st = ncr_delta (PROFILE.start,PROFILE.status);
 	if (st<0) return;	/* status  not reached  */
 
-	da = ncr_delta (PROFILE.start,PROFILE.data);
-	if (da<0) return;	/* No data transfer phase */
-
 	co = ncr_delta (PROFILE.start,PROFILE.command);
 	if (co<0) return;	/* command not executed */
 
@@ -7246,7 +8469,7 @@
 }
 #undef PROFILE
 
-#endif /* SCSI_NCR_PROFILE */
+#endif /* SCSI_NCR_PROFILE_SUPPORT */
 
 /*==========================================================
 **
@@ -7307,7 +8530,7 @@
 /*==========================================================
 **
 **	Determine the ncr's clock frequency.
-**	This is important for the negotiation
+**	This is essential for the negotiation
 **	of the synchronous transfer rate.
 **
 **==========================================================
@@ -7315,84 +8538,161 @@
 **	Note: we have to return the correct value.
 **	THERE IS NO SAVE DEFAULT VALUE.
 **
-**	We assume that all NCR based boards are delivered
-**	with a 40Mhz clock. Because we have to divide
-**	by an integer value greater than 3, only clock
-**	frequencies of 40Mhz (/4) or 50MHz (/5) permit
-**	the FAST-SCSI rate of 10MHz.
+**	Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock.
+**	53C860 and 53C875 rev. 1 support fast20 transfers but 
+**	do not have a clock doubler and so are provided with a 
+**	80 MHz clock. All other fast20 boards incorporate a doubler 
+**	and so should be delivered with a 40 MHz clock.
+**	The future fast40 chips (895/895) use a 40 Mhz base clock 
+**	and provide a clock quadrupler (160 Mhz). The code below 
+**	tries to deal as cleverly as possible with all this stuff.
 **
 **----------------------------------------------------------
 */
 
-#ifndef NCR_CLOCK
-#	define NCR_CLOCK 40
-#endif /* NCR_CLOCK */
+/*
+ *	Select NCR SCSI clock frequency
+ */
+static void ncr_selectclock(ncb_p np, u_char scntl3)
+{
+	if (np->multiplier < 2) {
+		OUTB(nc_scntl3,	scntl3);
+		return;
+	}
+
+	if (bootverbose >= 2)
+		printf ("%s: enabling clock multiplier\n", ncr_name(np));
 
+	OUTB(nc_stest1, DBLEN);	   /* Enable clock multiplier		  */
+	if (np->multiplier > 2) {  /* Poll bit 5 of stest4 for quadrupler */
+		int i = 20;
+		while (!(INB(nc_stest4) & LCKFRQ) && --i > 0)
+			DELAY(20);
+		if (!i)
+			printf("%s: the chip cannot lock the frequency\n", ncr_name(np));
+	} else			/* Wait 20 micro-seconds for doubler	*/
+		DELAY(20);
+	OUTB(nc_stest3, HSC);		/* Halt the scsi clock		*/
+	OUTB(nc_scntl3,	scntl3);
+	OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier	*/
+	OUTB(nc_stest3, 0x00);		/* Restart scsi clock 		*/
+}
 
-static void ncr_getclock (ncb_p np, u_char scntl3)
-{
-#if 0
-	u_char	tbl[5] = {6,2,3,4,6};
-	u_char	f;
-	u_char	ns_clock = (1000/NCR_CLOCK);
-
-	/*
-	**	Compute the best value for scntl3.
-	*/
-
-	f = (2 * MIN_SYNC_PD - 1) / ns_clock;
-	if (!f ) f=1;
-	if (f>4) f=4;
-	np -> ns_sync = (ns_clock * tbl[f]) / 2;
-	np -> rv_scntl3 = f<<4;
-
-	f = (2 * MIN_ASYNC_PD - 1) / ns_clock;
-	if (!f ) f=1;
-	if (f>4) f=4;
-	np -> ns_async = (ns_clock * tbl[f]) / 2;
-	np -> rv_scntl3 |= f;
-	if (DEBUG_FLAGS & DEBUG_TIMING)
-		printf ("%s: sclk=%d async=%d sync=%d (ns) scntl3=0x%x\n",
-		ncr_name (np), ns_clock, np->ns_async, np->ns_sync, np->rv_scntl3);
-#else
-	/*
-	 * If NCR53C875 chip with clock doubler enabled,
-	 *	disable clock doubler and assume 40 MHz clock.
-	 * If NCR53C860 chip assume 80 MHz clock.
+
+/*
+ *	calculate NCR SCSI clock frequency (in KHz)
+ */
+__initfunc(
+static unsigned ncrgetfreq (ncb_p np, int gen)
+)
+{
+	unsigned ms = 0;
+
+	/*
+	 * Measure GEN timer delay in order 
+	 * to calculate SCSI clock frequency
+	 *
+	 * This code will never execute too
+	 * many loop iterations (if DELAY is 
+	 * reasonably correct). It could get
+	 * too low a delay (too high a freq.)
+	 * if the CPU is slow executing the 
+	 * loop for some reason (an NMI, for
+	 * example). For this reason we will
+	 * if multiple measurements are to be 
+	 * performed trust the higher delay 
+	 * (lower frequency returned).
 	 */
+	OUTB (nc_stest1, 0);	/* make sure clock doubler is OFF */
+	OUTW (nc_sien , 0);	/* mask all scsi interrupts */
+	(void) INW (nc_sist);	/* clear pending scsi interrupt */
+	OUTB (nc_dien , 0);	/* mask all dma interrupts */
+	(void) INW (nc_sist);	/* another one, just to be sure :) */
+	OUTB (nc_scntl3, 4);	/* set pre-scaler to divide by 3 */
+	OUTB (nc_stime1, 0);	/* disable general purpose timer */
+	OUTB (nc_stime1, gen);	/* set to nominal delay of 1<<gen * 125us */
+	while (!(INW(nc_sist) & GEN) && ms++ < 100000)
+		DELAY(1000);	/* count ms */
+	OUTB (nc_stime1, 0);	/* disable general purpose timer */
+ 	/*
+ 	 * set prescaler to divide by whatever 0 means
+ 	 * 0 ought to choose divide by 2, but appears
+ 	 * to set divide by 3.5 mode in my 53c810 ...
+ 	 */
+ 	OUTB (nc_scntl3, 0);
+
+	if (bootverbose >= 2)
+		printf ("%s: Delay (GEN=%d): %u msec\n", ncr_name(np), gen, ms);
+  	/*
+ 	 * adjust for prescaler, and convert into KHz 
+  	 */
+	return ms ? ((1 << gen) * 4340) / ms : 0;
+}
 
-	switch(np->device_id) {
-	case PCI_DEVICE_ID_NCR_53C875:
-		if ((INB(nc_stest1) & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) {
-			if (bootverbose)
-				printf ("%s: disabling clock doubler\n", ncr_name(np));
-			OUTB(nc_stest1, 0);
-			scntl3	= 3;
-		}
-		break;
-	case PCI_DEVICE_ID_NCR_53C860:
-		scntl3	= 5;
-		break;
+/*
+ *	Get/probe NCR SCSI clock frequency
+ */
+__initfunc(
+static void ncr_getclock (ncb_p np, int mult)
+)
+{
+	unsigned char scntl3 = INB(nc_scntl3);
+	unsigned char stest1 = INB(nc_stest1);
+	unsigned f1;
+
+	np->multiplier = 1;
+	f1 = 40000;
+
+	/*
+	**	True with 875 or 895 with clock multiplier selected
+	*/
+	if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) {
+		if (bootverbose >= 2)
+			printf ("%s: clock multiplier found\n", ncr_name(np));
+		np->multiplier = mult;
 	}
 
 	/*
-	 *	For now just preserve the BIOS setting ...
-	 */
+	**	If multiplier not found or scntl3 not 7,5,3,
+	**	reset chip and get frequency from general purpose timer.
+	**	Otherwise trust scntl3 BIOS setting.
+	*/
+	if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) {
+		unsigned f2;
 
-	if ((scntl3 & 7) < 3) {
-		printf ("%s: assuming 40MHz clock\n", ncr_name(np));
-		scntl3 = 3; /* assume 40MHz if no value supplied by BIOS */
-	}
+		OUTB(nc_istat, SRST); DELAY(5); OUTB(nc_istat, 0);
 
-	np->ns_sync   = 25;
-	np->ns_async  = 50;
-	np->rv_scntl3 = ((scntl3 & 0x7) << 4) -0x20 + (scntl3 & 0x7);
-
-	if (bootverbose) {
-		printf ("%s: initial value of SCNTL3 = %02x, final = %02x\n",
-			ncr_name(np), scntl3, np->rv_scntl3);
+		(void) ncrgetfreq (np, 11);	/* throw away first result */
+		f1 = ncrgetfreq (np, 11);
+		f2 = ncrgetfreq (np, 11);
+
+		if (bootverbose)
+			printf ("%s: NCR clock is %uKHz, %uKHz\n", ncr_name(np), f1, f2);
+
+		if (f1 > f2) f1 = f2;		/* trust lower result	*/
+
+		if	(f1 <	45000)		f1 =  40000;
+		else if (f1 <	55000)		f1 =  50000;
+		else				f1 =  80000;
+
+		if (f1 < 80000 && mult > 1) {
+			if (bootverbose >= 2)
+				printf ("%s: clock multiplier assumed\n", ncr_name(np));
+			np->multiplier	= mult;
+		}
+	} else {
+		if	((scntl3 & 7) == 3)	f1 =  40000;
+		else if	((scntl3 & 7) == 5)	f1 =  80000;
+		else 				f1 = 160000;
+
+		f1 /= np->multiplier;
 	}
-#endif
+
+	/*
+	**	Compute controller synchronous parameters.
+	*/
+	f1		*= np->multiplier;
+	np->clock_khz	= f1;
 }
 
 /*===================== LINUX ENTRY POINTS SECTION ==========================*/
@@ -7409,29 +8709,108 @@
 #define ulong unsigned long
 #endif
 
-static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit, int board, int chip,
-	     uchar bus, uchar device_fn, int options);
-
-/*
-**   NCR53C8XX devices description table
+/* ---------------------------------------------------------------------
+**
+**	Driver setup from the boot command line
+**
+** ---------------------------------------------------------------------
 */
 
-static struct {
-     ushort pci_device_id;
-     int chip;
-     int max_revision;
-     int min_revision;
-} pci_chip_ids[] = { 
-     {PCI_DEVICE_ID_NCR_53C810,   810, -1, -1}, 
-/*   {PCI_DEVICE_ID_NCR_53C810AP, 810, -1, -1}, */
-     {PCI_DEVICE_ID_NCR_53C815,   815, -1, -1},
-     {PCI_DEVICE_ID_NCR_53C820,   820, -1, -1},
-     {PCI_DEVICE_ID_NCR_53C825,   825, -1, -1},
-     {PCI_DEVICE_ID_NCR_53C860,   860, -1, -1},
-     {PCI_DEVICE_ID_NCR_53C875,   875, -1, -1}
-};
+__initfunc(
+void ncr53c8xx_setup(char *str, int *ints)
+)
+{
+#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
+	char *cur = str;
+	char *pc, *pv;
+	int val;
+	int base;
+	int c;
+
+	while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+		val = 0;
+		pv = pc;
+		c = *++pv;
+		if	(c == 'n')
+			val = 0;
+		else if	(c == 'y')
+			val = 1;
+		else {
+			base = 0;
+#if 0
+			if	(c == '0') {
+				c = *pv++;
+				base = 8;
+			}
+			if	(c == 'x') {
+				++pv;
+				base = 16;
+			}
+			else if (c >= '0' && c <= '9')
+				base = 10;
+			else
+				break;
+#endif
+			val = (int) simple_strtoul(pv, NULL, base);
+		}
 
-#define NPCI_CHIP_IDS (sizeof (pci_chip_ids) / sizeof(pci_chip_ids[0]))
+		if	(!strncmp(cur, "mpar:", 5))
+			driver_setup.master_parity	= val;
+		else if	(!strncmp(cur, "spar:", 5))
+			driver_setup.scsi_parity	= val;
+		else if	(!strncmp(cur, "disc:", 5))
+			driver_setup.disconnection	= val;
+		else if	(!strncmp(cur, "specf:", 6))
+			driver_setup.special_features = val;
+		else if	(!strncmp(cur, "ultra:", 6))
+			driver_setup.ultra_scsi	= val;
+		else if	(!strncmp(cur, "fsn:", 4))
+			driver_setup.force_sync_nego	= val;
+		else if	(!strncmp(cur, "revprob:", 8))
+			driver_setup.reverse_probe	= val;
+		else if	(!strncmp(cur, "tags:", 5)) {
+			if (val > SCSI_NCR_MAX_TAGS)
+				val = SCSI_NCR_MAX_TAGS;
+			driver_setup.default_tags	= val;
+			}
+		else if	(!strncmp(cur, "sync:", 5))
+			driver_setup.default_sync	= val;
+		else if	(!strncmp(cur, "verb:", 5))
+			driver_setup.verbose	= val;
+		else if	(!strncmp(cur, "debug:", 6))
+			driver_setup.debug	= val;
+		else if	(!strncmp(cur, "burst:", 6))
+			driver_setup.burst_max	= val;
+		else if	(!strncmp(cur, "led:", 4))
+			driver_setup.led_pin	= val;
+		else if	(!strncmp(cur, "wide:", 5))
+			driver_setup.max_wide	= val? 1:0;
+		else if	(!strncmp(cur, "settle:", 7))
+			driver_setup.settle_delay= val;
+		else if	(!strncmp(cur, "diff:", 5))
+			driver_setup.diff_support= val;
+		else if	(!strncmp(cur, "irqm:", 5))
+			driver_setup.irqm	= val;
+		else if	(!strncmp(cur, "pcifix:", 7))
+			driver_setup.pci_fix_up	= val;
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+		else if	(!strncmp(cur, "nvram:", 6))
+			driver_setup.use_nvram	= val;
+#endif
+
+		else if	(!strncmp(cur, "safe:", 5) && val)
+			memcpy(&driver_setup, &driver_safe_setup, sizeof(driver_setup));
+		else
+			printf("ncr53c8xx_setup: unexpected boot option '%.*s' ignored\n", pc-cur+1, cur);
+
+		if ((cur = strchr(cur, ',')) != NULL)
+			++cur;
+	}
+#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
+}
+
+static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
+	     uchar bus, uchar device_fn, ncr_device *device);
 
 /*
 **   Linux entry point for NCR53C8XX devices detection routine.
@@ -7442,15 +8821,156 @@
 **   Read the PCI configuration and try to attach each
 **   detected NCR board.
 **
+**   If NVRAM is present, try to attach boards according to 
+**   the used defined boot order.
+**
 **   Returns the number of boards successfully attached.
 */
 
+__initfunc(
+static void ncr_print_driver_setup(void)
+)
+{
+#define YesNo(y)	y ? 'y' : 'n'
+	printk("ncr53c8xx: setup=disc:%c,specf:%c,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n",
+			YesNo(driver_setup.disconnection),
+			YesNo(driver_setup.special_features),
+			YesNo(driver_setup.ultra_scsi),
+			driver_setup.default_tags,
+			driver_setup.default_sync,
+			driver_setup.burst_max,
+			YesNo(driver_setup.max_wide),
+			driver_setup.diff_support);
+	printk("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,led:%c,settle:%d,irqm:%d\n",
+			YesNo(driver_setup.master_parity),
+			YesNo(driver_setup.scsi_parity),
+			YesNo(driver_setup.force_sync_nego),
+			driver_setup.verbose,
+			driver_setup.debug,
+			YesNo(driver_setup.led_pin),
+			driver_setup.settle_delay,
+			driver_setup.irqm);
+#undef YesNo
+}
+
+/*
+**   NCR53C8XX devices description table and chip ids list.
+*/
+
+static ncr_chip	ncr_chip_table[] __initdata	= SCSI_NCR_CHIP_TABLE;
+static ushort	ncr_chip_ids[]   __initdata	= SCSI_NCR_CHIP_IDS;
+
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+__initfunc(
+static int
+ncr_attach_using_nvram(Scsi_Host_Template *tpnt, int nvram_index, int count, ncr_device device[])
+)
+{
+	int i, j;
+	int attach_count = 0;
+	ncr_nvram  *nvram;
+	ncr_device *devp;
+
+	if (!nvram_index)
+		return 0;
+
+	/* find first Symbios NVRAM if there is one as we need to check it for host boot order */
+	for (i = 0, nvram_index = -1; i < count; i++) {
+		devp  = &device[i];
+		nvram = devp->nvram;
+		if (!nvram)
+			continue;
+		if (nvram->type == SCSI_NCR_SYMBIOS_NVRAM) {
+			if (nvram_index == -1)
+				nvram_index = i;
+#ifdef SCSI_NCR_DEBUG_NVRAM
+			printf("ncr53c8xx: NVRAM: Symbios format Boot Block, 53c%s, PCI bus %d, device %d, function %d\n",
+				devp->chip.name, devp->slot.bus, 
+				(int) (devp->slot.device_fn & 0xf8) >> 3, 
+				(int) devp->slot.device_fn & 7);
+			for (j = 0 ; j < 4 ; j++) {
+				Symbios_host *h = &nvram->data.Symbios.host[j];
+			printf("ncr53c8xx: BOOT[%d] device_id=%04x vendor_id=%04x device_fn=%02x io_port=%04x %s\n",
+				j,		h->device_id,	h->vendor_id,
+				h->device_fn,	h->io_port,
+				(h->flags & SYMBIOS_INIT_SCAN_AT_BOOT) ? "SCAN AT BOOT" : "");
+			}
+		}
+		else if (nvram->type == SCSI_NCR_TEKRAM_NVRAM) {
+			/* display Tekram nvram data */
+			printf("ncr53c8xx: NVRAM: Tekram format data, 53c%s, PCI bus %d, device %d, function %d\n",
+				devp->chip.name, devp->slot.bus, 
+				(int) (devp->slot.device_fn & 0xf8) >> 3, 
+				(int) devp->slot.device_fn & 7);
+#endif
+		}
+	}
+
+	if (nvram_index >= 0 && nvram_index < count)
+		nvram = device[nvram_index].nvram;
+	else
+		nvram = 0;
+
+	if (!nvram)
+		goto out;
+
+	/* 
+	** check devices in the boot record against devices detected. 
+	** attach devices if we find a match. boot table records that 
+	** do not match any detected devices will be ignored. 
+	** devices that do not match any boot table will not be attached
+	** here but will attempt to be attached during the device table 
+	** rescan.
+	*/
+     	for (i = 0; i < 4; i++) {
+		Symbios_host *h = &nvram->data.Symbios.host[i];
+		for (j = 0 ; j < count ; j++) {
+			devp = &device[j];
+			if (h->device_fn == devp->slot.device_fn &&
+#if 0	/* bus number location in nvram ? */
+			    h->bus	 == devp->slot.bus	 &&
+#endif
+			    h->device_id == devp->chip.device_id)
+				break;
+		}
+		if (j < count && !devp->attached &&
+		    !ncr_attach (tpnt, attach_count, devp)) {
+			attach_count++;
+			devp->attached = 1;
+		}
+	}
+
+out:
+	return attach_count;
+}
+#endif /* SCSI_NCR_NVRAM_SUPPORT */
+
+__initfunc(
 int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
+)
 {
-     int i;
-     int count = 0;			/* Number of boards detected */
-     uchar pci_bus, pci_device_fn;
-     short pci_index;	/* Device index to PCI BIOS calls */
+	int i, j;
+	int chips;
+	int count = 0;
+	uchar bus, device_fn;
+	short index;
+	int attach_count = 0;
+	ncr_device device[8];
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+	ncr_nvram  nvram[4];
+	int k, nvrams;
+#endif
+	int hosts;
+
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+	int nvram_index = 0;
+#endif
+	if (initverbose >= 2)
+		ncr_print_driver_setup();
+
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
+	ncr_debug = driver_setup.debug;
+#endif
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
      tpnt->proc_dir = &proc_scsi_ncr53c8xx;
@@ -7459,131 +8979,363 @@
 # endif
 #endif
 
-     if (pcibios_present()) {
-	  for (i = 0; i < NPCI_CHIP_IDS; ++i) 
-	       for (pci_index = 0;
-		    !pcibios_find_device(PCI_VENDOR_ID_NCR, 
-					 pci_chip_ids[i].pci_device_id, pci_index, &pci_bus, 
-					 &pci_device_fn);
-                    ++pci_index)
-		    if (!ncr53c8xx_pci_init(tpnt, count, 0, pci_chip_ids[i].chip, 
-			      pci_bus, pci_device_fn, /* no options */ 0))
-		    ++count;
-     }
+	/* 
+	** Detect all 53c8xx hosts and then attach them.
+	**
+	** If we are using NVRAM, once all hosts are detected, we need to check
+	** any NVRAM for boot order in case detect and boot order differ and
+	** attach them using the order in the NVRAM.
+	**
+	** If no NVRAM is found or data appears invalid attach boards in the 
+	** the order they are detected.
+	*/
 
-     return count;
-}
+	if (!pcibios_present())
+		return 0;
+
+	chips	= sizeof(ncr_chip_ids)	/ sizeof(ncr_chip_ids[0]);
+	hosts	= sizeof(device)	/ sizeof(device[0]);
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+	k = 0;
+	if (driver_setup.use_nvram & 0x1)
+		nvrams	= sizeof(nvram)	/ sizeof(nvram[0]);
+	else
+		nvrams	= 0;
+#endif
+
+	for (j = 0; j < chips ; ++j) {
+		i = driver_setup.reverse_probe ? chips-1 - j : j;
+		for (index = 0; ; index++) {
+			char *msg = "";
+			if ((pcibios_find_device(PCI_VENDOR_ID_NCR, ncr_chip_ids[i],
+						index, &bus, &device_fn)) ||
+			    (count == hosts))
+				break;
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+			device[count].nvram = k < nvrams ? &nvram[k] : 0;
+#else
+			device[count].nvram = 0;
+#endif
+			if (ncr53c8xx_pci_init(tpnt, bus, device_fn, &device[count])) {
+				device[count].nvram = 0;
+				continue;
+			}
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+			if (device[count].nvram) {
+				++k;
+				nvram_index |= device[count].nvram->type;
+				switch (device[count].nvram->type) {
+				case SCSI_NCR_TEKRAM_NVRAM:
+					msg = "with Tekram NVRAM";
+					break;
+				case SCSI_NCR_SYMBIOS_NVRAM:
+					msg = "with Symbios NVRAM";
+					break;
+				default:
+					msg = "";
+					device[count].nvram = 0;
+					--k;
+				}
+			}
+#endif
+			printf(KERN_INFO "ncr53c8xx: 53c%s detected %s\n",
+				device[count].chip.name, msg);
+
+			device[count].attached = 0;
+			++count;
+		}
+	}
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+	attach_count = ncr_attach_using_nvram(tpnt, nvram_index, count, device);
+#endif
+	/* 
+	** rescan device list to make sure all boards attached.
+	** devices without boot records will not be attached yet
+	** so try to attach them here.
+	*/
+	for (i= 0; i < count; i++) {
+		if ((!device[i].attached) && (!ncr_attach (tpnt, attach_count, &device[i]))) {
+ 			attach_count++;
+			device[i].attached = 1;
+		}
+	}
 
+	return attach_count;
+}
 
 /*
-**   Read the PCI configuration of a found NCR board and
-**   try yo attach it.
+**   Read and check the PCI configuration for any detected NCR 
+**   boards and save data for attaching after all boards have 
+**   been detected.
 */
 
-static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit, int board, int chip,
-		    uchar bus, uchar device_fn, int options)
-{
-     ushort vendor_id, device_id, command;
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
-     uint base, io_port; 
+__initfunc(
+static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
+			      uchar bus, uchar device_fn, ncr_device *device)
+)
+{
+	ushort vendor_id, device_id, command;
+	uchar cache_line_size, latency_timer;
+	uchar irq, revision;
+#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
+	uint base, io_port; 
+#else
+	ulong base, io_port; 
+#endif
+	int i, error;
+
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+	ncr_nvram *nvram = device->nvram;
+#endif
+	ncr_chip *chip;
+
+	printk(KERN_INFO "ncr53c8xx: at PCI bus %d, device %d, function %d\n",
+		bus, (int) (device_fn & 0xf8) >> 3, (int) device_fn & 7);
+	/*
+	 * Read info from the PCI config space
+	 */
+	if (
+		(error=pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, &vendor_id))	||
+		(error=pcibios_read_config_word(bus, device_fn, PCI_DEVICE_ID, &device_id))	||
+		(error=pcibios_read_config_word( bus, device_fn, PCI_COMMAND, &command))	||
+		(error=pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0,&io_port))	|| 
+		(error=pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1, &base))	||
+		(error=pcibios_read_config_byte(bus, device_fn, PCI_CLASS_REVISION,&revision))	||
+		(error=pcibios_read_config_byte(bus, device_fn, PCI_INTERRUPT_LINE, &irq))	||
+		(error=pcibios_read_config_byte(bus, device_fn, PCI_CACHE_LINE_SIZE, &cache_line_size)) ||
+		(error=pcibios_read_config_byte(bus, device_fn, PCI_LATENCY_TIMER, &latency_timer))
+	)
+		goto err_pcibios;
+
+	/*
+	 *	Check if the chip is supported
+	 */
+	chip = 0;
+	for (i = 0; i < sizeof(ncr_chip_table)/sizeof(ncr_chip_table[0]); i++) {
+		if (device_id != ncr_chip_table[i].device_id)
+			continue;
+		if (revision > ncr_chip_table[i].revision_id)
+			continue;
+		chip = &device->chip;
+		memcpy(chip, &ncr_chip_table[i], sizeof(*chip));
+		chip->revision_id = revision;
+		break;
+	}
+	if (!chip) {
+		printk("ncr53c8xx: not initializing, device not supported\n");
+		return -1;
+	}
+
+	/*
+	 * Check availability of IO space, memory space and master capability.
+	 */
+	if (command & PCI_COMMAND_IO) { 
+		if ((io_port & 3) != 1) {
+			printk("ncr53c8xx: disabling I/O mapping since base address 0 (0x%x)\n"
+				"           bits 0..1 indicate a non-IO mapping\n", (int) io_port);
+			io_port = 0;
+		}
+		else
+			io_port &= PCI_BASE_ADDRESS_IO_MASK;
+	}
+	else
+		io_port = 0;
+
+	if (command & PCI_COMMAND_MEMORY) {
+		if ((base & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
+			printk("ncr53c8xx: disabling memory mapping since base address 1\n"
+				"            contains a non-memory mapping\n");
+			base = 0;
+		}
+		else 
+			base &= PCI_BASE_ADDRESS_MEM_MASK;
+	}
+	else
+		base = 0;
+	
+	if (!io_port && !base) {
+		printk("ncr53c8xx: not initializing, both I/O and memory mappings disabled\n");
+		return -1;
+	}
+
+	if (io_port && check_region (io_port, 128)) {
+		printk("ncr53c8xx: IO region 0x%x to 0x%x is in use\n",
+			(int) io_port, (int) (io_port + 127));
+		return -1;
+	}
+	
+	if (!(command & PCI_COMMAND_MASTER)) {
+		printk("ncr53c8xx: not initializing, BUS MASTERING was disabled\n");
+		return -1;
+	}
+
+	/*
+	 * Fix some features according to driver setup.
+	 */
+	if (!driver_setup.special_features)
+		chip->features &= ~FE_SPECIAL_SET;
+	if (driver_setup.ultra_scsi < 2 && (chip->features & FE_ULTRA2)) {
+		chip->features |=  FE_ULTRA;
+		chip->features &= ~FE_ULTRA2;
+	}
+	if (driver_setup.ultra_scsi < 1)
+		chip->features &= ~FE_ULTRA;
+	if (!driver_setup.max_wide)
+		chip->features &= ~FE_WIDE;
+
+
+#ifdef	SCSI_NCR_PCI_FIX_UP_SUPPORT
+
+	/*
+	 * Try to fix up PCI config according to wished features.
+	 */
+#if defined(__i386) && !defined(MODULE)
+	if ((driver_setup.pci_fix_up & 1) &&
+	    (chip->features & FE_CLSE) && cache_line_size == 0) {
+		extern char x86;
+		switch(x86) {
+		case 4:	cache_line_size = 4; break;
+		case 5:	cache_line_size = 8; break;
+		}
+		if (cache_line_size)
+			error = pcibios_write_config_byte(bus, device_fn, PCI_CACHE_LINE_SIZE, cache_line_size);
+		if (error)
+			goto err_pcibios;
+		if (initverbose)
+			printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fix-up).\n", cache_line_size);
+	}
+
+	if ((driver_setup.pci_fix_up & 2) && cache_line_size &&
+	    (chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
+		command |= PCI_COMMAND_INVALIDATE;
+		error=pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+		if (error)
+			goto err_pcibios;
+		if (initverbose)
+			printk("ncr53c8xx: setting PCI_COMMAND_INVALIDATE bit (fix-up).\n");
+	}
+#endif
+	/*
+	 * Fix up for old chips that support READ LINE but not CACHE LINE SIZE.
+	 * - If CACHE LINE SIZE is unknown, set burst max to 32 bytes = 8 dwords
+	 *   and donnot enable READ LINE.
+	 * - Otherwise set it to the CACHE LINE SIZE (power of 2 assumed). 
+	 */
+
+	if (!(chip->features & FE_CLSE)) {
+		int burst_max = chip->burst_max;
+		if (cache_line_size == 0) {
+			chip->features	&= ~FE_ERL;
+			if (burst_max > 3)
+				burst_max = 3;
+		}
+		else {
+			while (cache_line_size < (1 << burst_max))
+				--burst_max;
+		}
+		chip->burst_max = burst_max;
+	}
+
+	/*
+	 * Tune PCI LATENCY TIMER according to burst max length transfer.
+	 * (latency timer >= burst length + 6, we add 10 to be quite sure)
+	 * If current value is zero, the device has probably been configured 
+	 * for no bursting due to some broken hardware.
+	 */
+
+	if (latency_timer == 0 && chip->burst_max)
+		printk("ncr53c8xx: PCI_LATENCY_TIMER=0, bursting should'nt be allowed.\n");
+
+	if ((driver_setup.pci_fix_up & 4) && chip->burst_max) {
+		uchar lt = (1 << chip->burst_max) + 6 + 10;
+		if (latency_timer < lt) {
+			latency_timer = lt;
+			if (initverbose)
+				printk("ncr53c8xx: setting PCI_LATENCY_TIMER to %d bus clocks (fix-up).\n", latency_timer);
+			error = pcibios_write_config_byte(bus, device_fn,
+					PCI_LATENCY_TIMER, latency_timer);
+			if (error)
+				goto err_pcibios;
+		}
+	}
+
+	/*
+	 * Fix up for recent chips that support CACHE LINE SIZE.
+	 * If PCI config space is not OK, remove features that shall not be 
+	 * used by the chip. No need to trigger possible chip bugs.
+	 */
+
+	if ((chip->features & FE_CLSE) && cache_line_size == 0) {
+		chip->features &= ~FE_CACHE_SET;
+		printk("ncr53c8xx: PCI_CACHE_LINE_SIZE not set, features based on CACHE LINE SIZE not used.\n");
+	}
+
+	if ((chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
+		chip->features &= ~FE_WRIE;
+		printk("ncr53c8xx: PCI_COMMAND_INVALIDATE not set, WRITE AND INVALIDATE not used\n");
+	}
+
+#endif	/* SCSI_NCR_PCI_FIX_UP_SUPPORT */
+
+ 	/* initialise ncr_device structure with items required by ncr_attach */
+	device->slot.bus	= bus;
+	device->slot.device_fn	= device_fn;
+	device->slot.base	= base;
+	device->slot.io_port	= io_port;
+	device->slot.irq	= irq;
+	device->attached	= 0;
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+	if (!nvram)
+		goto out;
+
+	/*
+	** Get access to chip IO registers
+	*/
+#ifdef NCR_IOMAPPED
+	request_region(io_port, 128, "ncr53c8xx");
+	device->slot.port = ioport;
+#else
+	device->slot.reg = (struct ncr_reg *) remap_pci_mem((ulong) base, 128);
+	if (!device->slot.reg)
+		goto out;
+#endif
+
+	/*
+	** Try to read SYMBIOS nvram.
+	** Data can be used to order booting of boards.
+	**
+	** Data is saved in ncr_device structure if NVRAM found. This
+	** is then used to find drive boot order for ncr_attach().
+	**
+	** NVRAM data is passed to Scsi_Host_Template later during ncr_attach()
+	** for any device set up.
+	**
+	** Try to read TEKRAM nvram if Symbios nvram not found.
+	*/
+
+	if	(!ncr_get_Symbios_nvram(&device->slot, &nvram->data.Symbios))
+		nvram->type = SCSI_NCR_SYMBIOS_NVRAM;
+	else if	(!ncr_get_Tekram_nvram(&device->slot, &nvram->data.Tekram))
+		nvram->type = SCSI_NCR_TEKRAM_NVRAM;
+	else
+		nvram->type = 0;
+out:
+	/*
+	** Release access to chip IO registers
+	*/
+#ifdef NCR_IOMAPPED
+	release_region(device->slot.port, 128);
 #else
-     ulong base, io_port; 
+	unmap_pci_mem((vm_offset_t) device->slot.reg, (u_long) 128);
 #endif
-     uchar irq, revision;
-     int error, expected_chip;
-     int expected_id = -1, max_revision = -1, min_revision = -1;
-     int i;
-
-     printk("ncr53c8xx : at PCI bus %d, device %d, function %d\n",
-	    bus, (int) (device_fn & 0xf8) >> 3, (int) device_fn & 7);
-
-     if (!pcibios_present()) {
-	  printk("ncr53c8xx : not initializing due to lack of PCI BIOS,\n");
-	  return -1;
-     }
-
-     if ((error = pcibios_read_config_word( bus, device_fn, PCI_VENDOR_ID,      &vendor_id)) ||
-	 (error = pcibios_read_config_word( bus, device_fn, PCI_DEVICE_ID,      &device_id)) ||
-	 (error = pcibios_read_config_word( bus, device_fn, PCI_COMMAND,        &command))   ||
-	 (error = pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, &io_port))   || 
-	 (error = pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1, &base))      ||
-	 (error = pcibios_read_config_byte (bus, device_fn, PCI_CLASS_REVISION, &revision))  ||
-	 (error = pcibios_read_config_byte (bus, device_fn, PCI_INTERRUPT_LINE, &irq))) {
-	  printk("ncr53c8xx : error %s not initializing due to error reading configuration space\n",
-		 pcibios_strerror(error));
-	  return -1;
-     }
-
-     if (vendor_id != PCI_VENDOR_ID_NCR) {
-	  printk("ncr53c8xx : not initializing, 0x%04x is not NCR vendor ID\n", (int) vendor_id);
-	  return -1;
-     }
-
-
-     if (command & PCI_COMMAND_IO) { 
-	  if ((io_port & 3) != 1) {
-	       printk("ncr53c8xx : disabling I/O mapping since base address 0 (0x%x)\n"
-		      "            bits 0..1 indicate a non-IO mapping\n", (int) io_port);
-	       io_port = 0;
-	  }
-	  else
-	       io_port &= PCI_BASE_ADDRESS_IO_MASK;
-     }
-     else
-	  io_port = 0;
 
-     if (command & PCI_COMMAND_MEMORY) {
-	  if ((base & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
-	       printk("ncr53c8xx : disabling memory mapping since base address 1\n"
-		      "            contains a non-memory mapping\n");
-	       base = 0;
-	  }
-	  else 
-	       base &= PCI_BASE_ADDRESS_MEM_MASK;
-     }
-     else
-	  base = 0;
-	
-     if (!io_port && !base) {
-	  printk("ncr53c8xx : not initializing, both I/O and memory mappings disabled\n");
-	  return -1;
-     }
-	
-     if (!(command & PCI_COMMAND_MASTER)) {
-	  printk ("ncr53c8xx : not initializing, BUS MASTERING was disabled\n");
-	  return -1;
-     }
-
-     for (i = 0; i < NPCI_CHIP_IDS; ++i) {
-	  if (device_id == pci_chip_ids[i].pci_device_id) {
-	       max_revision  = pci_chip_ids[i].max_revision;
-	       min_revision  = pci_chip_ids[i].min_revision;
-	       expected_chip = pci_chip_ids[i].chip;
-	  }
-	  if (chip == pci_chip_ids[i].chip)
-	       expected_id = pci_chip_ids[i].pci_device_id;
-     }
-
-     if (chip && device_id != expected_id) 
-	  printk("ncr53c8xx : warning : device id of 0x%04x doesn't\n"
-		 "            match expected 0x%04x\n",
-		  (unsigned int) device_id, (unsigned int) expected_id );
-    
-     if (max_revision != -1 && revision > max_revision) 
-	  printk("ncr53c8xx : warning : revision %d is greater than expected.\n",
-		 (int) revision);
-     else if (min_revision != -1 && revision < min_revision)
-	  printk("ncr53c8xx : warning : revision %d is lower than expected.\n",
-		 (int) revision);
-
-     if (io_port && check_region (io_port, 128)) {
-	  printk("ncr53c8xx : IO region 0x%x to 0x%x is in use\n",
-		 (int) io_port, (int) (io_port + 127));
-	  return -1;
-     }
+#endif	/* SCSI_NCR_NVRAM_SUPPORT */
+	return 0;     
 
-     return ncr_attach (tpnt, unit, device_id, revision, chip, base, io_port, 
-		       (int) irq, bus, (uchar) device_fn);
+err_pcibios:
+	printk("ncr53c8xx: error %s reading configuration space\n",
+		pcibios_strerror(error));
+	return -1;
 }
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0)
@@ -7596,13 +9348,18 @@
 
 	for (device = devlist; device; device = device->next) {
 		if (device->host == host) {
+#if SCSI_NCR_MAX_TAGS > 1
 			if (device->tagged_supported) {
 				device->queue_depth = SCSI_NCR_MAX_TAGS;
 			}
 			else {
-				device->queue_depth = 1;
+				device->queue_depth = 2;
 			}
-#ifdef DEBUG
+#else
+			device->queue_depth = 1;
+#endif
+
+#ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx_select_queue_depth: id=%d, lun=%d, queue_depth=%d\n",
 	device->id, device->lun, device->queue_depth);
 #endif
@@ -7618,19 +9375,19 @@
 int ncr53c8xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
 {
      int sts;
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx_queue_command\n");
 #endif
 
      if ((sts = ncr_queue_command(cmd, done)) != DID_OK) {
 	  cmd->result = ScsiResult(sts, 0);
 	  done(cmd);
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx : command not queued - result=%d\n", sts);
 #endif
           return sts;
      }
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx : command successfully queued\n");
 #endif
      return sts;
@@ -7648,8 +9405,13 @@
 {
      struct Scsi_Host *host;
      struct host_data *host_data;
+#if 0
+     u_long flags;
+
+     save_flags(flags); cli();
+#endif
 
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx : interrupt received\n");
 #endif
 
@@ -7658,12 +9420,20 @@
 	       host_data = (struct host_data *) host->hostdata;
 #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
 #   ifdef SCSI_NCR_SHARE_IRQ
-               if (dev_id == &host_data->ncb_data)
+               if (dev_id == host_data->ncb) {
+#else
+               if (1) {
 #   endif
 #endif
-	       ncr_intr(&host_data->ncb_data);
+                    if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
+	            ncr_exception(host_data->ncb);
+                    if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
+               }
 	  }
      }
+#if 0
+     restore_flags(flags);
+#endif
 }
 
 /*
@@ -7679,40 +9449,106 @@
 **   Linux entry point of reset() function
 */
 
-#if	LINUX_VERSION_CODE >= LinuxVersionCode(1,3,98)
+#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
+
 int ncr53c8xx_reset(Scsi_Cmnd *cmd, unsigned int reset_flags)
+{
+	int sts;
+	unsigned long flags;
+
+	printk("ncr53c8xx_reset: pid=%lu reset_flags=%x serial_number=%ld serial_number_at_timeout=%ld\n",
+		cmd->pid, reset_flags, cmd->serial_number, cmd->serial_number_at_timeout);
+
+	save_flags(flags); cli();
+
+	/*
+	 * We have to just ignore reset requests in some situations.
+	 */
+#if defined SCSI_RESET_NOT_RUNNING
+	if (cmd->serial_number != cmd->serial_number_at_timeout) {
+		sts = SCSI_RESET_NOT_RUNNING;
+		goto out;
+	}
+#endif
+	/*
+	 * If the mid-level driver told us reset is synchronous, it seems 
+	 * that we must call the done() callback for the involved command, 
+	 * even if this command was not queued to the low-level driver, 
+	 * before returning SCSI_RESET_SUCCESS.
+	 */
+
+	sts = ncr_reset_bus(cmd,
+	(reset_flags & (SCSI_RESET_SYNCHRONOUS | SCSI_RESET_ASYNCHRONOUS)) == SCSI_RESET_SYNCHRONOUS);
+	/*
+	 * Since we always reset the controller, when we return success, 
+	 * we add this information to the return code.
+	 */
+#if defined SCSI_RESET_HOST_RESET
+	if (sts == SCSI_RESET_SUCCESS)
+		sts |= SCSI_RESET_HOST_RESET;
+#endif
+
+out:
+	restore_flags(flags);
+	return sts;
+}
 #else
 int ncr53c8xx_reset(Scsi_Cmnd *cmd)
-#endif
 {
-#ifdef DEBUG
-printk("ncr53c8xx_reset : reset call\n");
-#endif
-	return ncr_reset_bus(cmd);
+	printk("ncr53c8xx_reset: command pid %lu\n", cmd->pid);
+	return ncr_reset_bus(cmd, 1);
 }
+#endif
 
 /*
 **   Linux entry point of abort() function
 */
 
+#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
+
+int ncr53c8xx_abort(Scsi_Cmnd *cmd)
+{
+	int sts;
+	unsigned long flags;
+
+	printk("ncr53c8xx_abort: pid=%lu serial_number=%ld serial_number_at_timeout=%ld\n",
+		cmd->pid, cmd->serial_number, cmd->serial_number_at_timeout);
+
+	save_flags(flags); cli();
+
+	/*
+	 * We have to just ignore abort requests in some situations.
+	 */
+	if (cmd->serial_number != cmd->serial_number_at_timeout) {
+		sts = SCSI_ABORT_NOT_RUNNING;
+		goto out;
+	}
+
+	sts = ncr_abort_command(cmd);
+out:
+	restore_flags(flags);
+	return sts;
+}
+#else
 int ncr53c8xx_abort(Scsi_Cmnd *cmd)
 {
-printk("ncr53c8xx_abort : abort call\n");
+	printk("ncr53c8xx_abort: command pid %lu\n", cmd->pid);
 	return ncr_abort_command(cmd);
 }
+#endif
 
 #ifdef MODULE
 int ncr53c8xx_release(struct Scsi_Host *host)
 {
      struct host_data *host_data;
-#ifdef DEBUG
+#ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx : release\n");
 #endif
 
      for (host = first_host; host; host = host->next) {
 	  if (host->hostt == the_template) {
 	       host_data = (struct host_data *) host->hostdata;
-	       ncr_detach(&host_data->ncb_data, host->irq);
+	       ncr_detach(host_data->ncb, host->irq);
 	  }
      }
 
@@ -7752,17 +9588,19 @@
 	}
 }
 
-static Scsi_Cmnd *remove_from_waiting_list(ncb_p np, Scsi_Cmnd *cmd)
+static Scsi_Cmnd *retrieve_from_waiting_list(int to_remove, ncb_p np, Scsi_Cmnd *cmd)
 {
 	Scsi_Cmnd *wcmd;
 
 	if (!(wcmd = np->waiting_list)) return 0;
 	while (wcmd->next_wcmd) {
 		if (cmd == (Scsi_Cmnd *) wcmd->next_wcmd) {
-			wcmd->next_wcmd = cmd->next_wcmd;
-			cmd->next_wcmd = 0;
+			if (to_remove) {
+				wcmd->next_wcmd = cmd->next_wcmd;
+				cmd->next_wcmd = 0;
+			}
 #ifdef DEBUG_WAITING_LIST
-	printf("%s: cmd %lx removed from waiting list\n", ncr_name(np), (u_long) cmd);
+	printf("%s: cmd %lx retrieved from waiting list\n", ncr_name(np), (u_long) cmd);
 #endif
 			return cmd;
 		}
@@ -7802,13 +9640,7 @@
 #undef next_wcmd
 
 /*
-**	In order to patch the SCSI script for SAVE/RESTORE DATA POINTER,
-**	we need the direction of transfer.
-**	Linux middle-level scsi driver does not provide this information.
-**	So we have to guess it.
-**	My documentation about SCSI-II standard is old. Probably some opcode
-**	are missing.
-**	If I do'nt know the command code, I assume input transfer direction.
+**	Returns data transfer direction for common op-codes.
 */
 
 static int guess_xfer_direction(int opcode)
@@ -7816,111 +9648,31 @@
 	int d;
 
 	switch(opcode) {
-	case 0x00:  /*	TEST UNIT READY			00 */
-	case 0x08:  /*	READ(6)				08 */
 	case 0x12:  /*	INQUIRY				12 */
 	case 0x4D:  /*	LOG SENSE			4D */
 	case 0x5A:  /*	MODE SENSE(10)			5A */
 	case 0x1A:  /*	MODE SENSE(6)			1A */
-	case 0x28:  /*	READ(10)			28 */
-	case 0xA8:  /*	READ(12)			A8 */
 	case 0x3C:  /*	READ BUFFER			3C */
 	case 0x1C:  /*	RECEIVE DIAGNOSTIC RESULTS	1C */
-	case 0xB7:  /*	READ DEFECT DATA(12)		B7 */
-	case 0xB8:  /*	READ ELEMENT STATUS		B8 */
-	            /*	GET WINDOW			25 */
-	case 0x25:  /*	READ CAPACITY			25 */
-	case 0x29:  /*	READ GENERATION			29 */
-	case 0x3E:  /*	READ LONG			3E */
-	            /*	GET DATA BUFFER STATUS		34 */
-	            /*	PRE-FETCH			34 */
-	case 0x34:  /*	READ POSITION			34 */
 	case 0x03:  /*	REQUEST SENSE			03 */
-	case 0x05:  /*	READ BLOCK LIMITS		05 */
-	case 0x0F:  /*	READ REVERSE			0F */
-	case 0x14:  /*	RECOVER BUFFERED DATA		14 */
-	case 0x2D:  /*	READ UPDATED BLOCK		2D */
-	case 0x37:  /*	READ DEFECT DATA(10)		37 */
-	case 0x42:  /*	READ SUB-CHANNEL		42 */
-	case 0x43:  /*	READ TOC			43 */
-	case 0x44:  /*	READ HEADER			44 */
-	case 0xC7:  /*  ???                  ???        C7 */
 		d = XferIn;
 		break;
 	case 0x39:  /*	COMPARE				39 */
 	case 0x3A:  /*	COPY AND VERIFY			3A */
-	            /*	PRINT				0A */
-	            /*	SEND MESSAGE(6)			0A */
-	case 0x0A:  /*	WRITE(6)			0A */
 	case 0x18:  /*	COPY				18 */
 	case 0x4C:  /*	LOG SELECT			4C */
 	case 0x55:  /*	MODE SELECT(10)			55 */
 	case 0x3B:  /*	WRITE BUFFER			3B */
 	case 0x1D:  /*	SEND DIAGNOSTIC			1D */
 	case 0x40:  /*	CHANGE DEFINITION		40 */
-	            /*	SEND MESSAGE(12)		AA */
-	case 0xAA:  /*	WRITE(12)			AA */
-	case 0xB6:  /*	SEND VOLUME TAG			B6 */
-	case 0x3F:  /*	WRITE LONG			3F */
-	case 0x04:  /*	FORMAT UNIT			04 */
-		    /*	INITIALIZE ELEMENT STATUS	07 */
-	case 0x07:  /*	REASSIGN BLOCKS			07 */
 	case 0x15:  /*	MODE SELECT(6)			15 */
-	case 0x24:  /*	SET WINDOW			24 */
-	case 0x2A:  /*	WRITE(10)			2A */
-	case 0x2E:  /*	WRITE AND VERIFY(10)		2E */
-	case 0xAE:  /*	WRITE AND VERIFY(12)		AE */
-	case 0xB0:  /*	SEARCH DATA HIGH(12)		B0 */
-	case 0xB1:  /*	SEARCH DATA EQUAL(12)		B1 */
-	case 0xB2:  /*	SEARCH DATA LOW(12)		B2 */
-	            /*	OBJECT POSITION			31 */
-	case 0x30:  /*	SEARCH DATA HIGH(10)		30 */
-	case 0x31:  /*	SEARCH DATA EQUAL(10)		31 */
-	case 0x32:  /*	SEARCH DATA LOW(10)		32 */
-	case 0x38:  /*	MEDIUM SCAN			38 */
-	case 0x3D:  /*	UPDATE BLOCK			3D */
-	case 0x41:  /*	WRITE SAME			41 */
-	            /*	LOAD UNLOAD			1B */
-	            /*	SCAN				1B */
-	case 0x1B:  /*	START STOP UNIT			1B */
 		d = XferOut;
 		break;
-	case 0x01:  /*	REZERO UNIT			01 */
-	            /*	SEEK(6)				0B */
-	case 0x0B:  /*	SLEW AND PRINT			0B */
-	            /*	SYNCHRONIZE BUFFER		10 */
-	case 0x10:  /*	WRITE FILEMARKS			10 */
-	case 0x11:  /*	SPACE				11 */
-	case 0x13:  /*	VERIFY				13 */
-	case 0x16:  /*	RESERVE UNIT			16 */
-	case 0x17:  /*	RELEASE UNIT			17 */
-	case 0x19:  /*	ERASE				19 */
-	            /*	LOCATE				2B */
-	            /*	POSITION TO ELEMENT		2B */
-	case 0x2B:  /*	SEEK(10)			2B */
-	case 0x1E:  /*	PREVENT ALLOW MEDIUM REMOVAL	1E */
-	case 0x2C:  /*	ERASE(10)			2C */
-	case 0xAC:  /*	ERASE(12)			AC */
-	case 0x2F:  /*	VERIFY(10)			2F */
-	case 0xAF:  /*	VERIFY(12)			AF */
-	case 0x33:  /*	SET LIMITS(10)			33 */
-	case 0xB3:  /*	SET LIMITS(12)			B3 */
-	case 0x35:  /*	SYNCHRONIZE CACHE		35 */
-	case 0x36:  /*	LOCK UNLOCK CACHE		36 */
-	case 0x45:  /*	PLAY AUDIO(10)			45 */
-	case 0x47:  /*	PLAY AUDIO MSF			47 */
-	case 0x48:  /*	PLAY AUDIO TRACK/INDEX		48 */
-	case 0x49:  /*	PLAY TRACK RELATIVE(10)		49 */
-	case 0xA9:  /*	PLAY TRACK RELATIVE(12)		A9 */
-	case 0x4B:  /*	PAUSE/RESUME			4B */
-	            /*	MOVE MEDIUM			A5 */
-	case 0xA5:  /*	PLAY AUDIO(12)			A5 */
-	case 0xA6:  /*	EXCHANGE MEDIUM			A6 */
-	case 0xB5:  /*	REQUEST VOLUME ELEMENT ADDRESS	B5 */
+	case 0x00:  /*	TEST UNIT READY			00 */
 		d = XferNone;
 		break;
 	default:
-		d = XferIn;
+		d = XferBoth;
 		break;
 	}
 
@@ -7940,6 +9692,8 @@
 **=========================================================================
 */
 
+#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
+
 #define is_digit(c)	((c) >= '0' && (c) <= '9')
 #define digit_to_bin(c)	((c) - '0')
 #define is_space(c)	((c) == ' ' || (c) == '\t')
@@ -8021,6 +9775,10 @@
 		uc->cmd = UC_SETFLAG;
 	else if	((arg_len = is_keyword(ptr, len, "clearprof")) != 0)
 		uc->cmd = UC_CLEARPROF;
+#ifdef	UC_DEBUG_ERROR_RECOVERY
+	else if	((arg_len = is_keyword(ptr, len, "debug_error_recovery")) != 0)
+		uc->cmd = UC_DEBUG_ERROR_RECOVERY;
+#endif
 	else
 		arg_len = 0;
 
@@ -8038,13 +9796,16 @@
 	case UC_SETWIDE:
 	case UC_SETFLAG:
 		SKIP_SPACES(1);
-		GET_INT_ARG(target);
+		if ((arg_len = is_keyword(ptr, len, "all")) != 0) {
+			ptr += arg_len; len -= arg_len;
+			uc->target = ~0;
+		} else {
+			GET_INT_ARG(target);
+			uc->target = (1<<target);
 #ifdef DEBUG_PROC_INFO
 printf("ncr_user_command: target=%ld\n", target);
 #endif
-		if (target > MAX_TARGET)
-			return -EINVAL;
-		uc->target = (1<<target);
+		}
 		break;
 	}
 
@@ -8074,6 +9835,8 @@
 			SKIP_SPACES(1);
 			if	((arg_len = is_keyword(ptr, len, "alloc")))
 				uc->data |= DEBUG_ALLOC;
+			else if	((arg_len = is_keyword(ptr, len, "phase")))
+				uc->data |= DEBUG_PHASE;
 			else if	((arg_len = is_keyword(ptr, len, "poll")))
 				uc->data |= DEBUG_POLL;
 			else if	((arg_len = is_keyword(ptr, len, "queue")))
@@ -8086,6 +9849,8 @@
 				uc->data |= DEBUG_SCRIPT;
 			else if	((arg_len = is_keyword(ptr, len, "tiny")))
 				uc->data |= DEBUG_TINY;
+			else if	((arg_len = is_keyword(ptr, len, "timing")))
+				uc->data |= DEBUG_TIMING;
 			else if	((arg_len = is_keyword(ptr, len, "nego")))
 				uc->data |= DEBUG_NEGO;
 			else if	((arg_len = is_keyword(ptr, len, "tags")))
@@ -8107,24 +9872,37 @@
 			SKIP_SPACES(1);
 			if	((arg_len = is_keyword(ptr, len, "trace")))
 				uc->data |= UF_TRACE;
+			else if	((arg_len = is_keyword(ptr, len, "no_disc")))
+				uc->data |= UF_NODISC;
 			else
 				return -EINVAL;
 			ptr += arg_len; len -= arg_len;
 		}
 		break;
+#ifdef	UC_DEBUG_ERROR_RECOVERY
+	case UC_DEBUG_ERROR_RECOVERY:
+		SKIP_SPACES(1);
+		if	((arg_len = is_keyword(ptr, len, "sge")))
+			uc->data = 1;
+		else if	((arg_len = is_keyword(ptr, len, "abort")))
+			uc->data = 2;
+		else if	((arg_len = is_keyword(ptr, len, "reset")))
+			uc->data = 3;
+		else if	((arg_len = is_keyword(ptr, len, "parity")))
+			uc->data = 4;
+		else if	((arg_len = is_keyword(ptr, len, "none")))
+			uc->data = 0;
+		else
+			return -EINVAL;
+		ptr += arg_len; len -= arg_len;
+		break;
+#endif
 	default:
 		break;
 	}
 
-	/*
-	** Not allow to disable tagged queue
-	*/ 
-	if (uc->cmd == UC_SETTAGS && uc->data < 1)
-		return -EINVAL;
-
 	if (len)
 		return -EINVAL;
-#ifdef SCSI_NCR_USER_COMMAND
 	else {
 		long flags;
 
@@ -8132,10 +9910,13 @@
 		ncr_usercmd (np);
 		restore_flags(flags);
 	}
-#endif
 	return length;
 }
 
+#endif	/* SCSI_NCR_USER_COMMAND_SUPPORT */
+
+#ifdef SCSI_NCR_USER_INFO_SUPPORT
+
 struct info_str
 {
 	char *buffer;
@@ -8182,6 +9963,8 @@
 **	Copy formatted profile information into the input buffer.
 */
 
+#define to_ms(t) ((t) * 1000 / HZ)
+
 static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len)
 {
 	struct info_str info;
@@ -8192,7 +9975,7 @@
 	info.pos	= 0;
 
 	copy_info(&info, "General information:\n");
-	copy_info(&info, "  Chip NCR53C%03d, ",	np->chip);
+	copy_info(&info, "  Chip NCR53C%s, ",	np->chip_name);
 	copy_info(&info, "device id 0x%x, ",	np->device_id);
 	copy_info(&info, "revision id 0x%x\n",	np->revision_id);
 
@@ -8200,12 +9983,19 @@
 	copy_info(&info, "IRQ number %d\n", (int) np->irq);
 
 #ifndef NCR_IOMAPPED
-	if (np->use_mmio)
+	if (np->reg)
 		copy_info(&info, "  Using memory mapped IO at virtual address 0x%lx\n",
-		                  (u_long) np->reg_remapped);
+		                  (u_long) np->reg);
 #endif
+	copy_info(&info, "  Synchronous period factor %d, ", (int) np->minsync);
+	copy_info(&info, "max commands per lun %d\n", SCSI_NCR_MAX_TAGS);
+
+	if (driver_setup.debug || driver_setup.verbose > 1) {
+		copy_info(&info, "  Debug flags 0x%x, ", driver_setup.debug);
+		copy_info(&info, "verbosity level %d\n", driver_setup.verbose);
+	}
 
-#ifdef SCSI_NCR_PROFILE
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 	copy_info(&info, "Profiling information:\n");
 	copy_info(&info, "  %-12s = %lu\n", "num_trans",np->profile.num_trans);
 	copy_info(&info, "  %-12s = %lu\n", "num_kbytes",np->profile.num_kbytes);
@@ -8213,15 +10003,17 @@
 	copy_info(&info, "  %-12s = %lu\n", "num_break",np->profile.num_break);
 	copy_info(&info, "  %-12s = %lu\n", "num_int",	np->profile.num_int);
 	copy_info(&info, "  %-12s = %lu\n", "num_fly",	np->profile.num_fly);
-	copy_info(&info, "  %-12s = %lu\n", "ms_setup",	np->profile.ms_setup);
-	copy_info(&info, "  %-12s = %lu\n", "ms_data",	np->profile.ms_data);
-	copy_info(&info, "  %-12s = %lu\n", "ms_disc",	np->profile.ms_disc);
-	copy_info(&info, "  %-12s = %lu\n", "ms_post",	np->profile.ms_post);
+	copy_info(&info, "  %-12s = %lu\n", "ms_setup",	to_ms(np->profile.ms_setup));
+	copy_info(&info, "  %-12s = %lu\n", "ms_data",	to_ms(np->profile.ms_data));
+	copy_info(&info, "  %-12s = %lu\n", "ms_disc",	to_ms(np->profile.ms_disc));
+	copy_info(&info, "  %-12s = %lu\n", "ms_post",	to_ms(np->profile.ms_post));
 #endif
 	
 	return info.pos > info.offset? info.pos - info.offset : 0;
 }
 
+#endif /* SCSI_NCR_USER_INFO_SUPPORT */
+
 /*
 **	Entry point of the scsi proc fs of the driver.
 **	- func = 0 means read  (returns profile data)
@@ -8243,7 +10035,7 @@
 	for (host = first_host; host; host = host->next) {
 		if (host->hostt == the_template && host->host_no == hostno) {
 			host_data = (struct host_data *) host->hostdata;
-			ncb = &host_data->ncb_data;
+			ncb = host_data->ncb;
 			break;
 		}
 	}
@@ -8252,26 +10044,486 @@
 		return -EINVAL;
 
 	if (func) {
+#ifdef	SCSI_NCR_USER_COMMAND_SUPPORT
 		retv = ncr_user_command(ncb, buffer, length);
-#ifdef DEBUG_PROC_INFO
-printf("ncr_user_command: retv=%d\n", retv);
+#else
+		retv = -EINVAL;
 #endif
 	}
 	else {
 		if (start)
 			*start = buffer;
+#ifdef SCSI_NCR_USER_INFO_SUPPORT
 		retv = ncr_host_info(ncb, buffer, offset, length);
+#else
+		retv = -EINVAL;
+#endif
 	}
 
 	return retv;
 }
 
+
 /*=========================================================================
 **	End of proc file system stuff
 **=========================================================================
 */
 #endif
 
+
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+
+/* ---------------------------------------------------------------------
+**
+**	Try reading Symbios format nvram
+**
+** ---------------------------------------------------------------------
+**
+** GPOI0 - data in/data out
+** GPIO1 - clock
+**
+**	return 0 if NVRAM data OK, 1 if NVRAM data not OK
+** ---------------------------------------------------------------------
+*/
+
+#define SET_BIT 0
+#define CLR_BIT 1
+#define SET_CLK 2
+#define CLR_CLK 3
+
+static u_short nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl);
+static void nvram_start(ncr_slot *np, u_char *gpreg);
+static void nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl);
+static void nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl);
+static void nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl);
+static void nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl);
+static void nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg);
+static void nvram_stop(ncr_slot *np, u_char *gpreg);
+static void nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode);
+
+__initfunc(
+static int ncr_get_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram)
+)
+{
+	static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0};
+	u_char	gpcntl, gpreg;
+	u_char	old_gpcntl, old_gpreg;
+	u_short	csum;
+	u_char	ack_data;
+	int	retv = 1;
+
+	/* save current state of GPCNTL and GPREG */
+	old_gpreg	= INB (nc_gpreg);
+	old_gpcntl	= INB (nc_gpcntl);
+	gpcntl		= old_gpcntl & 0xfc;
+
+	/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
+	OUTB (nc_gpreg,  old_gpreg);
+	OUTB (nc_gpcntl, gpcntl);
+
+	/* this is to set NVRAM into a known state with GPIO0/1 both low */
+	gpreg = old_gpreg;
+	nvram_setBit(np, 0, &gpreg, CLR_CLK);
+	nvram_setBit(np, 0, &gpreg, CLR_BIT);
+		
+	/* now set NVRAM inactive with GPIO0/1 both high */
+	nvram_stop(np, &gpreg);
+	
+	/* activate NVRAM */
+	nvram_start(np, &gpreg);
+
+	/* write device code and random address MSB */
+	nvram_write_byte(np, &ack_data,
+		0xa0 | ((SYMBIOS_NVRAM_ADDRESS >> 7) & 0x0e), &gpreg, &gpcntl);
+	if (ack_data & 0x01)
+		goto out;
+
+	/* write random address LSB */
+	nvram_write_byte(np, &ack_data,
+		(SYMBIOS_NVRAM_ADDRESS & 0x7f) << 1, &gpreg, &gpcntl);
+	if (ack_data & 0x01)
+		goto out;
+
+	/* regenerate START state to set up for reading */
+	nvram_start(np, &gpreg);
+	
+	/* rewrite device code and address MSB with read bit set (lsb = 0x01) */
+	nvram_write_byte(np, &ack_data,
+		0xa1 | ((SYMBIOS_NVRAM_ADDRESS >> 7) & 0x0e), &gpreg, &gpcntl);
+	if (ack_data & 0x01)
+		goto out;
+
+	/* now set up GPIO0 for inputting data */
+	gpcntl |= 0x01;
+	OUTB (nc_gpcntl, gpcntl);
+		
+	/* input all active data - only part of total NVRAM */
+	csum = nvram_read_data(np,
+			(u_char *) nvram, sizeof(*nvram), &gpreg, &gpcntl);
+
+	/* finally put NVRAM back in inactive mode */
+	gpcntl &= 0xfe;
+	OUTB (nc_gpcntl, gpcntl);
+	nvram_stop(np, &gpreg);
+	
+#ifdef SCSI_NCR_DEBUG_NVRAM
+printf("ncr53c8xx: NvRAM marker=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n",
+	nvram->start_marker,
+	nvram->trailer[0], nvram->trailer[1], nvram->trailer[2],
+	nvram->trailer[3], nvram->trailer[4], nvram->trailer[5],
+	nvram->byte_count, sizeof(*nvram) - 12,
+	nvram->checksum, csum);
+#endif
+
+	/* check valid NVRAM signature, verify byte count and checksum */
+	if (nvram->start_marker == 0 &&
+	    !memcmp(nvram->trailer, Symbios_trailer, 6) &&
+	    nvram->byte_count == sizeof(*nvram) - 12 &&
+	    csum == nvram->checksum)
+		retv = 0;
+out:
+	/* return GPIO0/1 to original states after having accessed NVRAM */
+	OUTB (nc_gpcntl, old_gpcntl);
+	OUTB (nc_gpreg,  old_gpreg);
+
+	return retv;
+}
+
+/*
+ * Read Symbios NvRAM data and compute checksum.
+ */
+__initfunc(
+static u_short nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl)
+)
+{
+	int	x;
+	u_short	csum;
+
+	for (x = 0; x < len; x++) 
+		nvram_read_byte(np, &data[x], (x == (len - 1)), gpreg, gpcntl);
+
+	for (x = 6, csum = 0; x < len - 6; x++)
+		csum += data[x];
+
+	return csum;
+}
+
+/*
+ * Send START condition to NVRAM to wake it up.
+ */
+__initfunc(
+static void nvram_start(ncr_slot *np, u_char *gpreg)
+)
+{
+	nvram_setBit(np, 1, gpreg, SET_BIT);
+	nvram_setBit(np, 0, gpreg, SET_CLK);
+	nvram_setBit(np, 0, gpreg, CLR_BIT);
+	nvram_setBit(np, 0, gpreg, CLR_CLK);
+}
+
+/*
+ * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK,
+ * GPIO0 must already be set as an output
+ */
+__initfunc(
+static void nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl)
+)
+{
+	int x;
+	
+	for (x = 0; x < 8; x++)
+		nvram_doBit(np, 0, (write_data >> (7 - x)) & 0x01, gpreg);
+		
+	nvram_readAck(np, ack_data, gpreg, gpcntl);
+}
+
+/*
+ * READ a byte from the NVRAM and then send an ACK to say we have got it,
+ * GPIO0 must already be set as an input
+ */
+__initfunc(
+static void nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl)
+)
+{
+	int x;
+	u_char read_bit;
+
+	*read_data = 0;
+	for (x = 0; x < 8; x++) {
+		nvram_doBit(np, &read_bit, 1, gpreg);
+		*read_data |= ((read_bit & 0x01) << (7 - x));
+	}
+
+	nvram_writeAck(np, ack_data, gpreg, gpcntl);
+}
+
+/*
+ * Output an ACK to the NVRAM after reading,
+ * change GPIO0 to output and when done back to an input
+ */
+__initfunc(
+static void nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl)
+)
+{
+	OUTB (nc_gpcntl, *gpcntl & 0xfe);
+	nvram_doBit(np, 0, write_bit, gpreg);
+	OUTB (nc_gpcntl, *gpcntl);
+}
+
+/*
+ * Input an ACK from NVRAM after writing,
+ * change GPIO0 to input and when done back to an output
+ */
+__initfunc(
+static void nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl)
+)
+{
+	OUTB (nc_gpcntl, *gpcntl | 0x01);
+	nvram_doBit(np, read_bit, 1, gpreg);
+	OUTB (nc_gpcntl, *gpcntl);
+}
+
+/*
+ * Read or write a bit to the NVRAM,
+ * read if GPIO0 input else write if GPIO0 output
+ */
+__initfunc(
+static void nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg)
+)
+{
+	nvram_setBit(np, write_bit, gpreg, SET_BIT);
+	nvram_setBit(np, 0, gpreg, SET_CLK);
+	if (read_bit)
+		*read_bit = INB (nc_gpreg);
+	nvram_setBit(np, 0, gpreg, CLR_CLK);
+	nvram_setBit(np, 0, gpreg, CLR_BIT);
+}
+
+/*
+ * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!!
+ */
+__initfunc(
+static void nvram_stop(ncr_slot *np, u_char *gpreg)
+)
+{
+	nvram_setBit(np, 0, gpreg, SET_CLK);
+	nvram_setBit(np, 1, gpreg, SET_BIT);
+}
+
+/*
+ * Set/clear data/clock bit in GPIO0
+ */
+__initfunc(
+static void nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
+)
+{
+	DELAY(5);
+	switch (bit_mode){
+	case SET_BIT:
+		*gpreg |= write_bit;
+		break;
+	case CLR_BIT:
+		*gpreg &= 0xfe;
+		break;
+	case SET_CLK:
+		*gpreg |= 0x02;
+		break;
+	case CLR_CLK:
+		*gpreg &= 0xfd;
+		break;
+
+	}
+	OUTB (nc_gpreg, *gpreg);
+	DELAY(5);
+}
+
+#undef SET_BIT 0
+#undef CLR_BIT 1
+#undef SET_CLK 2
+#undef CLR_CLK 3
+
+
+/* ---------------------------------------------------------------------
+**
+**	Try reading Tekram format nvram
+**
+** ---------------------------------------------------------------------
+**
+** GPOI0 - data in
+** GPIO1 - data out
+** GPIO2 - clock
+** GPIO4 - chip select
+**
+**	return 0 if NVRAM data OK, 1 if NVRAM data not OK
+** ---------------------------------------------------------------------
+*/
+
+static u_short Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg);
+static void Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg);
+static void Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg);
+static void Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg);
+static void Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg);
+static void Tnvram_Stop(ncr_slot *np, u_char *gpreg);
+static void Tnvram_Clk(ncr_slot *np, u_char *gpreg);
+
+__initfunc(
+static int ncr_get_Tekram_nvram (ncr_slot *np, Tekram_nvram *nvram)
+)
+{
+	u_char gpcntl, gpreg;
+	u_char old_gpcntl, old_gpreg;
+	u_short csum;
+
+	/* save current state of GPCNTL and GPREG */
+	old_gpreg	= INB (nc_gpreg);
+	old_gpcntl	= INB (nc_gpcntl);
+
+	/* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in,
+	   1/2/4 out */
+	gpreg = old_gpreg & 0xe9;
+	OUTB (nc_gpreg, gpreg);
+	gpcntl = (old_gpcntl & 0xe9) | 0x09;
+	OUTB (nc_gpcntl, gpcntl);
+
+	/* input all of NVRAM, 64 words */
+	csum = Tnvram_read_data(np, (u_short *) nvram,
+			sizeof(*nvram) / sizeof(short), &gpreg);
+	
+	/* return GPIO0/1/2/4 to original states after having accessed NVRAM */
+	OUTB (nc_gpcntl, old_gpcntl);
+	OUTB (nc_gpreg,  old_gpreg);
+
+	/* check data valid */
+	if (csum != 0x1234)
+		return 1;
+
+	return 0;
+}
+
+/*
+ * Read Tekram NvRAM data and compute checksum.
+ */
+__initfunc(
+static u_short Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg)
+)
+{
+	u_char	read_bit;
+	u_short	csum;
+	int	x;
+
+	for (x = 0, csum = 0; x < len; x++)  {
+
+		/* output read command and address */
+		Tnvram_Send_Command(np, 0x180 | x, &read_bit, gpreg);
+		if (read_bit & 0x01)
+			return 0; /* Force bad checksum */
+
+		Tnvram_Read_Word(np, &data[x], gpreg);
+		csum += data[x];
+
+		Tnvram_Stop(np, gpreg);
+	}
+
+	return csum;
+}
+
+/*
+ * Send read command and address to NVRAM
+ */
+__initfunc(
+static void Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg)
+)
+{
+	int x;
+
+	/* send 9 bits, start bit (1), command (2), address (6)  */
+	for (x = 0; x < 9; x++)
+		Tnvram_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg);
+
+	*read_bit = INB (nc_gpreg);
+}
+
+/*
+ * READ a byte from the NVRAM
+ */
+__initfunc(
+static void Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg)
+)
+{
+	int x;
+	u_char read_bit;
+
+	*nvram_data = 0;
+	for (x = 0; x < 16; x++) {
+		Tnvram_Read_Bit(np, &read_bit, gpreg);
+
+		if (read_bit & 0x01)
+			*nvram_data |=  (0x01 << (15 - x));
+		else
+			*nvram_data &= ~(0x01 << (15 - x));
+	}
+}
+
+/* 
+ * Read bit from NVRAM
+ */
+__initfunc(
+static void Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
+)
+{
+	DELAY(2);
+	Tnvram_Clk(np, gpreg);
+	*read_bit = INB (nc_gpreg);
+}
+
+/*
+ * Write bit to GPIO0
+ */
+__initfunc(
+static void Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg)
+)
+{
+	if (write_bit & 0x01)
+		*gpreg |= 0x02;
+	else
+		*gpreg &= 0xfd;
+		
+	*gpreg |= 0x10;
+		
+	OUTB (nc_gpreg, *gpreg);
+	DELAY(2);
+
+	Tnvram_Clk(np, gpreg);
+}
+
+/*
+ * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!!
+ */
+__initfunc(
+static void Tnvram_Stop(ncr_slot *np, u_char *gpreg)
+)
+{
+	*gpreg &= 0xef;
+	OUTB (nc_gpreg, *gpreg);
+	DELAY(2);
+
+	Tnvram_Clk(np, gpreg);
+}
+
+/*
+ * Pulse clock bit in GPIO0
+ */
+__initfunc(
+static void Tnvram_Clk(ncr_slot *np, u_char *gpreg)
+)
+{
+	OUTB (nc_gpreg, *gpreg | 0x04);
+	DELAY(2);
+	OUTB (nc_gpreg, *gpreg);
+}
+
+#endif	/* SCSI_NCR_NVRAM_SUPPORT */
+
 /*
 **	Module stuff
 */
diff -urN linux-2.0.31-pre5/drivers/scsi/ncr53c8xx.h linux-2.0.31-pre6/drivers/scsi/ncr53c8xx.h
--- linux-2.0.31-pre5/drivers/scsi/ncr53c8xx.h	1997-03-11 15:40:02.000000000 -0800
+++ linux-2.0.31-pre6/drivers/scsi/ncr53c8xx.h	2003-08-15 15:04:01.000000000 -0700
@@ -42,7 +42,10 @@
 #ifndef NCR53C8XX_H
 #define NCR53C8XX_H
 
-/*********** LINUX SPECIFIC SECTION ******************/
+/*
+**	Name and revision of the driver
+*/
+#define SCSI_NCR_DRIVER_NAME		"ncr53c8xx - revision 2.4"
 
 /*
 **	Check supported Linux versions
@@ -65,28 +68,6 @@
 #define LINUX_VERSION_CODE LinuxVersionCode(1,2,13)
 #endif
 
-#if !defined(VERSION)
-#define VERSION		((LINUX_VERSION_CODE >> 16) & 0xff)
-#define PATCHLEVEL	((LINUX_VERSION_CODE >> 8)  & 0xff)
-#define SUBLEVEL	((LINUX_VERSION_CODE >> 0)  & 0xff)
-#endif
-
-#if	VERSION == 0 || VERSION > 3
-#	error Only Linux version 1 and probable 2 or 3 supported.
-#endif
-
-#if	VERSION == 1 && PATCHLEVEL == 2
-#	if	SUBLEVEL != 13
-#		error Only sublevel 13 of Linux 1.2 is supported.
-#	endif
-#endif
-
-#if	VERSION == 1 && PATCHLEVEL == 3
-#	if	SUBLEVEL < 45
-#		error Only sublevels >=45 of Linux 1.3 are supported.
-#	endif
-#endif
-
 /*
 **	Normal IO or memory mapped IO.
 **
@@ -108,53 +89,168 @@
 #endif
 
 /*
-**	Avoid to change these constants, unless you know what you are doing.
+**	If you want a driver as small as possible, donnot define the 
+**	following options.
+*/
+
+#define SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
+#define SCSI_NCR_DEBUG_INFO_SUPPORT
+#define SCSI_NCR_PCI_FIX_UP_SUPPORT
+#ifdef	SCSI_NCR_PROC_INFO_SUPPORT
+#	define	SCSI_NCR_PROFILE_SUPPORT
+#	define	SCSI_NCR_USER_COMMAND_SUPPORT
+#	define	SCSI_NCR_USER_INFO_SUPPORT
+/* #	define	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT */
+#endif
+
+/*==========================================================
+**
+** nvram settings - #define SCSI_NCR_NVRAM_SUPPORT to enable
+**
+**==========================================================
+*/
+
+#ifdef CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT
+#define SCSI_NCR_NVRAM_SUPPORT
+/* #define SCSI_NCR_DEBUG_NVRAM */
+#endif
+
+/* ---------------------------------------------------------------------
+** Take into account kernel configured parameters.
+** Most of these options can be overridden at startup by a command line.
+** ---------------------------------------------------------------------
 */
 
+/*
+ * For Ultra2 SCSI support option, use special features and allow 40Mhz 
+ * synchronous data transfers.
+ */
+#define	SCSI_NCR_SETUP_SPECIAL_FEATURES		(1)
+#define SCSI_NCR_SETUP_ULTRA_SCSI		(2)
+#define SCSI_NCR_MAX_SYNC			(40)
+
+/*
+ * Allow tags from 2 to 12, default 4
+ */
+#ifdef	CONFIG_SCSI_NCR53C8XX_MAX_TAGS
+#if	CONFIG_SCSI_NCR53C8XX_MAX_TAGS < 2
+#define SCSI_NCR_MAX_TAGS	(2)
+#elif	CONFIG_SCSI_NCR53C8XX_MAX_TAGS > 12
+#define SCSI_NCR_MAX_TAGS	(12)
+#else
+#define	SCSI_NCR_MAX_TAGS	CONFIG_SCSI_NCR53C8XX_MAX_TAGS
+#endif
+#else
 #define SCSI_NCR_MAX_TAGS	(4)
-#define SCSI_NCR_ALWAYS_SIMPLE_TAG
+#endif
 
-#ifdef CONFIG_SCSI_NCR53C8XX_IOMAPPED
+/*
+ * Allow tagged command queuing support if configured with default number 
+ * of tags set to max (see above).
+ */
+#ifdef	CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE
+#define	SCSI_NCR_SETUP_DEFAULT_TAGS	SCSI_NCR_MAX_TAGS
+#else
+#define	SCSI_NCR_SETUP_DEFAULT_TAGS	(0)
+#endif
+
+/*
+ * Use normal IO if configured. Forced for alpha.
+ */
+#if defined(CONFIG_SCSI_NCR53C8XX_IOMAPPED) || defined(__alpha__)
 #define	SCSI_NCR_IOMAPPED
 #endif
 
-#ifndef CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE
-#define SCSI_NCR_TAGGED_QUEUE_DISABLED
+/*
+ * Sync transfer frequency at startup.
+ * Allow from 5Mhz to 40Mhz default 10 Mhz.
+ */
+#ifndef	CONFIG_SCSI_NCR53C8XX_SYNC
+#define	CONFIG_SCSI_NCR53C8XX_SYNC	(5)
+#elif	CONFIG_SCSI_NCR53C8XX_SYNC > SCSI_NCR_MAX_SYNC
+#define	SCSI_NCR_SETUP_DEFAULT_SYNC	SCSI_NCR_MAX_SYNC
 #endif
 
-#ifdef CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
-#define SCSI_NCR_NO_DISCONNECT
+#if	CONFIG_SCSI_NCR53C8XX_SYNC == 0
+#define	SCSI_NCR_SETUP_DEFAULT_SYNC	(255)
+#elif	CONFIG_SCSI_NCR53C8XX_SYNC <= 5
+#define	SCSI_NCR_SETUP_DEFAULT_SYNC	(50)
+#elif	CONFIG_SCSI_NCR53C8XX_SYNC <= 20
+#define	SCSI_NCR_SETUP_DEFAULT_SYNC	(250/(CONFIG_SCSI_NCR53C8XX_SYNC))
+#elif	CONFIG_SCSI_NCR53C8XX_SYNC <= 33
+#define	SCSI_NCR_SETUP_DEFAULT_SYNC	(11)
+#else
+#define	SCSI_NCR_SETUP_DEFAULT_SYNC	(10)
 #endif
 
-#ifdef CONFIG_SCSI_NCR53C8XX_FORCE_ASYNCHRONOUS
-#define SCSI_NCR_FORCE_ASYNCHRONOUS
+/*
+ * Disallow disconnections at boot-up
+ */
+#ifdef CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
+#define SCSI_NCR_SETUP_DISCONNECTION	(0)
+#else
+#define SCSI_NCR_SETUP_DISCONNECTION	(1)
 #endif
 
+/*
+ * Force synchronous negotiation for all targets
+ */
 #ifdef CONFIG_SCSI_NCR53C8XX_FORCE_SYNC_NEGO
-#define SCSI_NCR_FORCE_SYNC_NEGO
+#define SCSI_NCR_SETUP_FORCE_SYNC_NEGO	(1)
+#else
+#define SCSI_NCR_SETUP_FORCE_SYNC_NEGO	(0)
 #endif
 
+/*
+ * Disable master parity checking (flawed hardwares need that)
+ */
 #ifdef CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK
-#define SCSI_NCR_DISABLE_MPARITY_CHECK
+#define SCSI_NCR_SETUP_MASTER_PARITY	(0)
+#else
+#define SCSI_NCR_SETUP_MASTER_PARITY	(1)
 #endif
 
+/*
+ * Disable scsi parity checking (flawed devices may need that)
+ */
 #ifdef CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK
-#define SCSI_NCR_DISABLE_PARITY_CHECK
+#define SCSI_NCR_SETUP_SCSI_PARITY	(0)
+#else
+#define SCSI_NCR_SETUP_SCSI_PARITY	(1)
 #endif
 
-#if 0
-#define SCSI_NCR_SEGMENT_SIZE	(512)
+/*
+ * Vendor specific stuff
+ */
+#ifdef CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
+#define SCSI_NCR_SETUP_LED_PIN		(1)
+#define SCSI_NCR_SETUP_DIFF_SUPPORT	(3)
+#else
+#define SCSI_NCR_SETUP_LED_PIN		(0)
+#define SCSI_NCR_SETUP_DIFF_SUPPORT	(0)
 #endif
 
-#define SCSI_NCR_MAX_SCATTER	(128)
+/*
+ * Settle time after reset at boot-up
+ */
+#define SCSI_NCR_SETUP_SETTLE_TIME	(2)
+
+/*
+**	Other parameters not configurable with "make config"
+**	Avoid to change these constants, unless you know what you are doing.
+*/
+
+#define SCSI_NCR_ALWAYS_SIMPLE_TAG
+#define SCSI_NCR_MAX_SCATTER	(127)
 #define SCSI_NCR_MAX_TARGET	(16)
 #define SCSI_NCR_MAX_HOST	(2)
-#define SCSI_NCR_SETTLE_TIME	(2)
 #define SCSI_NCR_TIMEOUT_ALERT	(3*HZ)
 
 #define SCSI_NCR_CAN_QUEUE	(7*SCSI_NCR_MAX_TAGS)
 #define SCSI_NCR_CMD_PER_LUN	(SCSI_NCR_MAX_TAGS)
-#define SCSI_NCR_SG_TABLESIZE	(SCSI_NCR_MAX_SCATTER-1)
+#define SCSI_NCR_SG_TABLESIZE	(SCSI_NCR_MAX_SCATTER)
+
+#define SCSI_NCR_TIMER_INTERVAL	((HZ+5-1)/5)
 
 #if 1 /* defined CONFIG_SCSI_MULTI_LUN */
 #define SCSI_NCR_MAX_LUN	(8)
@@ -162,8 +258,6 @@
 #define SCSI_NCR_MAX_LUN	(1)
 #endif
 
-#define SCSI_NCR_TIMER_INTERVAL	((HZ+5-1)/5)
-
 /*
 **	Define Scsi_Host_Template parameters
 **
@@ -196,7 +290,7 @@
 
 #if	LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
 
-#define NCR53C8XX {NULL,NULL,NULL,NULL,"ncr53c8xx (rel 1.12d)", ncr53c8xx_detect,\
+#define NCR53C8XX {NULL,NULL,NULL,NULL,SCSI_NCR_DRIVER_NAME, ncr53c8xx_detect,\
     	ncr53c8xx_release, /* info */ NULL, /* command, deprecated */ NULL, 		\
 	ncr53c8xx_queue_command, ncr53c8xx_abort, ncr53c8xx_reset,	\
         NULL /* slave attach */, scsicam_bios_param, /* can queue */ SCSI_NCR_CAN_QUEUE,\
@@ -207,7 +301,7 @@
 #else
 
 
-#define NCR53C8XX {NULL, NULL, "ncr53c8xx (rel 1.12d)", ncr53c8xx_detect,\
+#define NCR53C8XX {NULL, NULL, SCSI_NCR_DRIVER_NAME, ncr53c8xx_detect,\
     	ncr53c8xx_release, /* info */ NULL, /* command, deprecated */ NULL, 		\
 	ncr53c8xx_queue_command, ncr53c8xx_abort, ncr53c8xx_reset,	\
         NULL /* slave attach */, scsicam_bios_param, /* can queue */ SCSI_NCR_CAN_QUEUE,\
@@ -222,6 +316,200 @@
 #ifndef HOSTS_C
 
 /*
+**	NCR53C8XX Device Ids
+*/
+
+#ifndef PCI_DEVICE_ID_NCR_53C810
+#define PCI_DEVICE_ID_NCR_53C810 1
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C810AP
+#define PCI_DEVICE_ID_NCR_53C810AP 5
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C815
+#define PCI_DEVICE_ID_NCR_53C815 4
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C820
+#define PCI_DEVICE_ID_NCR_53C820 2
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C825
+#define PCI_DEVICE_ID_NCR_53C825 3
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C860
+#define PCI_DEVICE_ID_NCR_53C860 6
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C875
+#define PCI_DEVICE_ID_NCR_53C875 0xf
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C875J
+#define PCI_DEVICE_ID_NCR_53C875J 0x8f
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C885
+#define PCI_DEVICE_ID_NCR_53C885 0xd
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C895
+#define PCI_DEVICE_ID_NCR_53C895 0xc
+#endif
+
+#ifndef PCI_DEVICE_ID_NCR_53C896
+#define PCI_DEVICE_ID_NCR_53C896 0xb
+#endif
+
+/*
+**   NCR53C8XX devices features table.
+*/
+typedef struct {
+	unsigned short	device_id;
+	unsigned short	revision_id;
+	char	*name;
+	unsigned char	burst_max;
+	unsigned char	offset_max;
+	unsigned char	nr_divisor;
+	unsigned int	features;
+#define FE_LED0		(1<<0)
+#define FE_WIDE		(1<<1)
+#define FE_ULTRA	(1<<2)
+#define FE_ULTRA2	(1<<3)
+#define FE_DBLR		(1<<4)
+#define FE_QUAD		(1<<5)
+#define FE_ERL		(1<<6)
+#define FE_CLSE		(1<<7)
+#define FE_WRIE		(1<<8)
+#define FE_ERMP		(1<<9)
+#define FE_BOF		(1<<10)
+#define FE_DFS		(1<<11)
+#define FE_PFEN		(1<<12)
+#define FE_LDSTR	(1<<13)
+#define FE_RAM		(1<<14)
+#define FE_CLK80	(1<<15)
+#define FE_CACHE_SET	(FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP)
+#define FE_SCSI_SET	(FE_WIDE|FE_ULTRA|FE_ULTRA2|FE_DBLR|FE_QUAD|F_CLK80)
+#define FE_SPECIAL_SET	(FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM)
+} ncr_chip;
+
+#define SCSI_NCR_CHIP_TABLE						\
+{									\
+ {PCI_DEVICE_ID_NCR_53C810, 0x0f, "810",  4,  8, 4,			\
+ FE_ERL}								\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C810, 0xff, "810a", 4,  8, 4,			\
+ FE_CACHE_SET|FE_LDSTR|FE_PFEN|FE_BOF}					\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C815, 0xff, "815",  4,  8, 4,			\
+ FE_ERL|FE_BOF}								\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C820, 0xff, "820",  4,  8, 4,			\
+ FE_WIDE|FE_ERL}							\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C825, 0x0f, "825",  4,  8, 4,			\
+ FE_WIDE|FE_ERL|FE_BOF}							\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C825, 0xff, "825a", 7,  8, 4,			\
+ FE_WIDE|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}		\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C860, 0xff, "860",  4,  8, 5,			\
+ FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN|FE_RAM}	\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C875, 0x01, "875",  7, 16, 5,			\
+ FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C875, 0xff, "875",  7, 16, 5,			\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C875J, 0xff, "875J",  7, 16, 5,			\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C885, 0xff, "885",  7, 16, 5,			\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C895, 0xff, "895",  7, 31, 7,			\
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C896, 0xff, "896",  7, 31, 7,			\
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+}
+
+/*
+ * List of supported NCR chip ids
+ */
+#define SCSI_NCR_CHIP_IDS		\
+{					\
+	PCI_DEVICE_ID_NCR_53C810,	\
+	PCI_DEVICE_ID_NCR_53C815,	\
+	PCI_DEVICE_ID_NCR_53C820,	\
+	PCI_DEVICE_ID_NCR_53C825,	\
+	PCI_DEVICE_ID_NCR_53C860,	\
+	PCI_DEVICE_ID_NCR_53C875,	\
+	PCI_DEVICE_ID_NCR_53C875J,	\
+	PCI_DEVICE_ID_NCR_53C885,	\
+	PCI_DEVICE_ID_NCR_53C895,	\
+	PCI_DEVICE_ID_NCR_53C896	\
+}
+
+/*
+**	Initial setup.
+**	Can be overriden at startup by a command line.
+*/
+#define SCSI_NCR_DRIVER_SETUP			\
+{						\
+	SCSI_NCR_SETUP_MASTER_PARITY,		\
+	SCSI_NCR_SETUP_SCSI_PARITY,		\
+	SCSI_NCR_SETUP_DISCONNECTION,		\
+	SCSI_NCR_SETUP_SPECIAL_FEATURES,	\
+	SCSI_NCR_SETUP_ULTRA_SCSI,		\
+	SCSI_NCR_SETUP_FORCE_SYNC_NEGO,		\
+	0,					\
+	0,					\
+	1,					\
+	1,					\
+	SCSI_NCR_SETUP_DEFAULT_TAGS,		\
+	SCSI_NCR_SETUP_DEFAULT_SYNC,		\
+	0x00,					\
+	7,					\
+	SCSI_NCR_SETUP_LED_PIN,			\
+	1,					\
+	SCSI_NCR_SETUP_SETTLE_TIME,		\
+	SCSI_NCR_SETUP_DIFF_SUPPORT,		\
+	0					\
+}
+
+/*
+**	Boot fail safe setup.
+**	Override initial setup from boot command line:
+**	ncr53c8xx=safe:y
+*/
+#define SCSI_NCR_DRIVER_SAFE_SETUP		\
+{						\
+	0,					\
+	1,					\
+	0,					\
+	0,					\
+	0,					\
+	0,					\
+	0,					\
+	0,					\
+	1,					\
+	2,					\
+	0,					\
+	255,					\
+	0x00,					\
+	255,					\
+	0,					\
+	0,					\
+	10,					\
+	1,					\
+	1					\
+}
+
+/*
 **	Define the table of target capabilities by host and target
 **
 **	If you have problems with a scsi device, note the host unit and the
@@ -309,38 +597,6 @@
 #endif
 #endif
 
-/*
-**	NCR53C8XX Device Ids
-*/
-
-#ifndef PCI_DEVICE_ID_NCR_53C810
-#define PCI_DEVICE_ID_NCR_53C810 1
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C810AP
-#define PCI_DEVICE_ID_NCR_53C810AP 5
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C815
-#define PCI_DEVICE_ID_NCR_53C815 4
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C820
-#define PCI_DEVICE_ID_NCR_53C820 2
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C825
-#define PCI_DEVICE_ID_NCR_53C825 3
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C860
-#define PCI_DEVICE_ID_NCR_53C860 6
-#endif
-
-#ifndef PCI_DEVICE_ID_NCR_53C875
-#define PCI_DEVICE_ID_NCR_53C875 0xf
-#endif
-
 /**************** ORIGINAL CONTENT of ncrreg.h from FreeBSD ******************/
 
 /*-----------------------------------------------------------------
@@ -365,6 +621,7 @@
 
 /*03*/  u_char    nc_scntl3;    /* cnf system clock dependent       */
 	#define   EWS     0x08  /* cmd: enable wide scsi         [W]*/
+	#define   ULTRA   0x80  /* cmd: ULTRA enable                */
 
 /*04*/  u_char    nc_scid;	/* cnf host adapter scsi address    */
 	#define   RRE     0x40  /* r/w:e enable response to resel.  */
@@ -418,6 +675,7 @@
         #define   ILF1    0x80  /* sta: data in SIDL register msb[W]*/
         #define   ORF1    0x40  /* sta: data in SODR register msb[W]*/
         #define   OLF1    0x20  /* sta: data in SODL register msb[W]*/
+        #define   DM      0x04  /* sta: DIFFSENS mismatch (895/6 only) */
         #define   LDSC    0x02  /* sta: disconnect & reconnect      */
 
 /*10*/  u_int32    nc_dsa;	/* --> Base page                    */
@@ -443,13 +701,20 @@
 	#define   CSIGP   0x40
 
 /*1b*/  u_char    nc_ctest3;
-	#define   CLF	  0x04	/* clear scsi fifo		    */
+	#define   FLF     0x08  /* cmd: flush dma fifo              */
+	#define   CLF	  0x04	/* cmd: clear dma fifo		    */
+	#define   FM      0x02  /* mod: fetch pin mode              */
+	#define   WRIE    0x01  /* mod: write and invalidate enable */
 
 /*1c*/  u_int32    nc_temp;	/* ### Temporary stack              */
 
 /*20*/	u_char	  nc_dfifo;
 /*21*/  u_char    nc_ctest4;
+	#define   BDIS    0x80  /* mod: burst disable               */
+	#define   MPEE    0x08  /* mod: master parity error enable  */
+
 /*22*/  u_char    nc_ctest5;
+	#define   DFS     0x20  /* mod: dma fifo size               */
 /*23*/  u_char    nc_ctest6;
 
 /*24*/  u_int32    nc_dbc;	/* ### Byte count and command       */
@@ -459,18 +724,31 @@
 /*34*/  u_int32    nc_scratcha;  /* ??? Temporary register a         */
 
 /*38*/  u_char    nc_dmode;
+	#define   BL_2    0x80  /* mod: burst length shift value +2 */
+	#define   BL_1    0x40  /* mod: burst length shift value +1 */
+	#define   ERL     0x08  /* mod: enable read line            */
+	#define   ERMP    0x04  /* mod: enable read multiple        */
+	#define   BOF     0x02  /* mod: burst op code fetch         */
+
 /*39*/  u_char    nc_dien;
 /*3a*/  u_char    nc_dwt;
 
 /*3b*/  u_char    nc_dcntl;	/* --> Script execution control     */
-        #define   SSM     0x10  /* mod: single step mode            */
-        #define   STD     0x04  /* cmd: start dma mode              */
-	#define	  NOCOM   0x01	/* cmd: protect sfbr while reselect */
+
+	#define   CLSE    0x80  /* mod: cache line size enable      */
+	#define   PFF     0x40  /* cmd: pre-fetch flush             */
+	#define   PFEN    0x20  /* mod: pre-fetch enable            */
+	#define   SSM     0x10  /* mod: single step mode            */
+	#define   IRQM    0x08  /* mod: irq mode (1 = totem pole !) */
+	#define   STD     0x04  /* cmd: start dma mode              */
+	#define   IRQD    0x02  /* mod: irq disable                 */
+ 	#define	  NOCOM   0x01	/* cmd: protect sfbr while reselect */
 
 /*3c*/  u_int32    nc_adder;
 
 /*40*/  u_short   nc_sien;	/* -->: interrupt enable            */
 /*42*/  u_short   nc_sist;	/* <--: interrupt status            */
+        #define   SBMC    0x1000/* sta: SCSI Bus Mode Change (895/6 only) */
         #define   STO     0x0400/* sta: timeout (select)            */
         #define   GEN     0x0200/* sta: timeout (general)           */
         #define   HTH     0x0100/* sta: timeout (handshake)         */
@@ -496,6 +774,7 @@
 /*4d*/  u_char    nc_stest1;
 	#define   DBLEN   0x08	/* clock doubler running		*/
 	#define   DBLSEL  0x04	/* clock doubler selected		*/
+  
 
 /*4e*/  u_char    nc_stest2;
 	#define   ROF     0x40	/* reset scsi offset (after gross error!) */
@@ -503,10 +782,18 @@
 
 /*4f*/  u_char    nc_stest3;
 	#define   TE     0x80	/* c: tolerAnt enable */
+	#define   HSC    0x20	/* c: Halt SCSI Clock */
 	#define   CSF    0x02	/* c: clear scsi fifo */
 
 /*50*/  u_short   nc_sidl;	/* Lowlevel: latched from scsi data */
-/*52*/  u_short   nc_52_;
+/*52*/  u_char    nc_stest4;
+	#define   SMODE  0xc0	/* SCSI bus mode      (895/6 only) */
+	#define    SMODE_HVD 0x40	/* High Voltage Differential       */
+	#define    SMODE_SE  0x80	/* Single Ended                    */
+	#define    SMODE_LVD 0xc0	/* Low Voltage Differential        */
+	#define   LCKFRQ 0x20	/* Frequency Lock (895/6 only)     */
+
+/*53*/	u_char    nc_53_;
 /*54*/  u_short   nc_sodl;	/* Lowlevel: data out to scsi data  */
 /*56*/  u_short   nc_56_;
 /*58*/  u_short   nc_sbdl;	/* Lowlevel: data from scsi data    */
@@ -659,10 +946,18 @@
 **	<< source_address >>
 **	<< destination_address >>
 **
+**	SCR_COPY   sets the NO FLUSH option by default.
+**	SCR_COPY_F does not set this option.
+**
+**	For chips which do not support this option,
+**	ncr_copy_and_bind() will remove this bit.
 **-----------------------------------------------------------
 */
 
-#define SCR_COPY(n) (0xc0000000 | (n))
+#define SCR_NO_FLUSH 0x01000000
+
+#define SCR_COPY(n) (0xc0000000 | SCR_NO_FLUSH | (n))
+#define SCR_COPY_F(n) (0xc0000000 | (n))
 
 /*-----------------------------------------------------------
 **
@@ -768,6 +1063,7 @@
 **-----------------------------------------------------------
 */
 
+#define SCR_NO_OP        0x80000000
 #define SCR_JUMP        0x80080000
 #define SCR_JUMPR       0x80880000
 #define SCR_CALL        0x88080000
diff -urN linux-2.0.31-pre5/drivers/scsi/README.ncr53c8xx linux-2.0.31-pre6/drivers/scsi/README.ncr53c8xx
--- linux-2.0.31-pre5/drivers/scsi/README.ncr53c8xx	1996-09-20 07:00:34.000000000 -0700
+++ linux-2.0.31-pre6/drivers/scsi/README.ncr53c8xx	2003-08-15 15:04:01.000000000 -0700
@@ -1,10 +1,10 @@
-The linux NCR53C8XX driver README file
+The Linux NCR53C8XX driver README file
 
 Written by Gerard Roudier <groudier@club-internet.fr>
 21 Rue Carnot
 95170 DEUIL LA BARRE - FRANCE
 
-12 June 1995
+19 June 1997
 ===============================================================================
 
 1.  Introduction
@@ -21,15 +21,31 @@
       8.4  Set order type for tagged command
       8.5  Set debug mode
       8.6  Clear profile counters
+      8.7  Set flag (no_sync)
+      8.8  Debug error recovery
 9.  Configuration parameters
-10. Some constants and flags of the ncr53c8xx.h header files
-11. Provided files
-12. Installation procedure for Linux version 1
-13. Installation procedure for Linux version 2
-14. Control commands under linux-1.2.13
-15. Known problems
-      15.1 Tagged commands with Iomega Jaz device
-      15.2 Tagged command queueing cannot be disabled at run time
+10. Boot setup commands
+      10.1 Syntax
+      10.2 Available arguments
+      10.3 Advised boot setup commands
+      10.4 PCI configuration fix-up boot option
+      10.5 Serial NVRAM support boot option
+11. Some constants and flags of the ncr53c8xx.h header file
+12. Installation
+      12.1 Provided files
+      12.2 Installation procedure
+13. Control commands under linux-1.2.13
+14. Known problems
+      14.1 Tagged commands with Iomega Jaz device
+      14.2 Device names change when another controller is added
+15. SCSI problem troubleshooting
+16. Synchonous transfer negotiation tables
+      16.1 Synchronous timings for 53C875 and 53C860 Ultra-SCSI controllers
+      16.2 Synchronous timings for fast SCSI-2 53C8XX controllers
+17. Serial NVRAM support (by Richard Waltham)
+      17.1 Features
+      17.2 Symbios NVRAM layout
+      17.3 Tekram  NVRAM layout
 
 ===============================================================================
 
@@ -43,21 +59,37 @@
           Wolfgang Stanglmeier        <wolf@cologne.de>
           Stefan Esser                <se@mi.Uni-Koeln.de>
 
-You can find technical information about the NCR 8xx family in the PCI-HOWTO 
-written by Michael Will and in the SCSI-HOWTO written by Drew Eckhardt.
+You can find technical information about the NCR 8xx family in the
+PCI-HOWTO written by Michael Will and in the SCSI-HOWTO written by
+Drew Eckhardt.
 
 Information about new chips is available at SYMBIOS web server:
-          http://www.symbios.com
 
-This short documentation only describes the features of the NCR53C8XX driver, 
-configuration parameters and control commands available through the proc SCSI
-file system read / write operations.
+          http://www.symbios.com/
 
-This driver has been tested OK with linux/i386  and is currently untested
-under linux/Alpha. If you intend to use this driver under linux/Alpha, just 
-try it first with read-only or mounted read-only devices.
+SCSI standard documentations are available at SYMBIOS ftp server:
 
-I am not a native speaker of English and there are probably lots of 
+          ftp://ftp.symbios.com/
+
+Usefull SCSI tools written by Eric Youngdale are available at tsx-11:
+
+          ftp://tsx-11.mit.edu/pub/linux/ALPHA/scsi/scsiinfo-X.Y.tar.gz
+          ftp://tsx-11.mit.edu/pub/linux/ALPHA/scsi/scsidev-X.Y.tar.gz
+
+These tools are not ALPHA but quite clean and work quite well.
+It is essential you have the 'scsiinfo' package.
+
+This short documentation only describes the features of the NCR53C8XX
+driver, configuration parameters and control commands available
+through the proc SCSI file system read / write operations.
+
+This driver has been tested OK with linux/i386 and Linux/Alpha.
+
+Latest driver version and patches are available at:
+
+          ftp://linux.wauug.org/pub/roudier
+
+I am not a native speaker of English and there are probably lots of
 mistakes in this README file. Any help will be welcome.
 
 
@@ -71,8 +103,8 @@
 	SCSI parity checking
 	Master parity checking
 
-"Wide negotiation" is supported for chips that allow it.
-The following table shows some characteristics of NCR 8xx family chips:
+"Wide negotiation" is supported for chips that allow it.  The
+following table shows some characteristics of NCR 8xx family chips:
 
        On board                        Supported by    Tested with
 Chip   SDMS BIOS   Wide   Ultra SCSI   the driver      the driver
@@ -81,12 +113,12 @@
 810A       N         N        N            Y             Y
 815        Y         N        N            Y             Y
 825        Y         Y        N            Y             Y
-825A       Y         Y        N            Y             Not yet
-875        Y         Y        Y(1)         Y             Not yet
-
-(1) Ultra SCSI extensions will be supported in a future release of the 
-    driver.
+825A       Y         Y        N            Y             Y
+860        N         N        Y            Y             Y
+875        Y         Y        Y            Y             Y
+895        Y         Y        Y(1)         Y             not yet 
 
+(1) The 895 chip is supported 'on paper'.
 
 3. Summary of other supported features.
 
@@ -97,45 +129,58 @@
         Debugging information: written to syslog (expert only)
 	Scatter / gather
 	Shared interrupt
+        Boot setup commands
+        Serial NVRAM:          Symbios and Tekram formats
 
 
 4. Memory mapped I/O versus normal I/O
 
-Memory mapped I/O has less latency than normal I/O.
-Since linux-1.3.x, memory mapped I/O is used rather than normal I/O.
-Memory mapped I/O seems to work fine on most hardware configurations, but some 
-poorly designed motherboards may break this feature.
-
-During the initialization phase, the driver first tries to use memory mapped
-I/O.  If nothing seems wrong, it will use memory mapped I/O.
-If a flaw is detected, it will use normal I/O.
+Memory mapped I/O has less latency than normal I/O.  Since
+linux-1.3.x, memory mapped I/O is used rather than normal I/O.  Memory
+mapped I/O seems to work fine on most hardware configurations, but
+some poorly designed motherboards may break this feature.
 
-However, it's possible that memory mapped I/O does not work properly and the 
-driver has not detected the problem.
-
-The configuration option CONFIG_SCSI_NCR53C8XX_IOMAPPED forces the 
+The configuration option CONFIG_SCSI_NCR53C8XX_IOMAPPED forces the
 driver to use normal I/O in all cases.
 
 
 5. Tagged command queueing
 
-Some SCSI devices do not properly support tagged command queuing.
-A safe configuration is to not enable tagged command queuing support at 
-boot-up, and to enable support of it with the control command "settags" 
-described further in this text.
-
-Once you are sure that all your devices properly support tagged command queuing,
-you can enable it by default with the CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE 
-configuration option.
+Some SCSI devices do not properly support tagged command queuing.  A
+safe configuration is to not enable tagged command queuing support at
+boot-up, and to enable support of it with the control command
+"settags" described further in this text.
+
+Once you are sure that all your devices properly support tagged
+command queuing, you can enable it by default with the
+CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE configuration option.
+
+The maximum number of simultaneous tagged commands queued to a device
+is currently set to 4 by default. It is defined in the file
+ncr53c8xx.h by SCSI_NCR_MAX_TAGS. This value is suitable for most SCSI
+disks.  With large SCSI disks (> 2GB, cache > 512KB average seek time
+< 10 ms), 8 tagged commands may give better performance.
+
+In some special conditions, some SCSI disk firmwares may return a
+QUEUE FULL status for a SCSI command. This behaviour is managed by the
+driver by the following heuristic:
+
+- Each time a QUEUE FULL status is returned, tagged command queueing is 
+  temporarily disabled. 
+
+- Every 100 successfully completed SCSI commands, if allowed by the
+  current limit, the maximum number of queueable commands is
+  incremented and tagged command queueing is reenabled.
 
 
 6. Parity checking
 
-The driver supports SCSI parity checking and PCI bus master parity checking.
-These features must be enabled in order to ensure safe data transfers.
-However, some flawed devices or mother boards will have problems with 
-parity. You can disable parity by choosing first "CONFIG_EXPERIMENTAL".
-Then, "make config" will allow to set the following configuration options:
+The driver supports SCSI parity checking and PCI bus master parity
+checking.  These features must be enabled in order to ensure safe data
+transfers.  However, some flawed devices or mother boards will have
+problems with parity. You can disable parity by choosing first
+"CONFIG_EXPERIMENTAL".  Then, "make config" will allow to set the
+following configuration options:
 
    CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK  (disable SCSI parity checking)
    CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK (disable master parity checking)
@@ -145,16 +190,19 @@
 
 Profiling information is available through the proc SCSI file system.
 The device associated with a host has the following pathname:
+
           /proc/scsi/ncr53c8xx/N     (N=0,1,2 ....)
 
 Generally, only 1 board is used on hardware configuration, and that device is:
           /proc/scsi/ncr53c8xx/0
 
-However, if the driver has been made as module, the number of the hosts is 
-incremented each time the driver is loaded.
+However, if the driver has been made as module, the number of the
+hosts is incremented each time the driver is loaded.
 
 In order to display profiling information, just enter:
+
          cat /proc/scsi/ncr53c8xx/0
+
 and you will get something like the following text:
 
 -------------------------------------------------------
@@ -162,6 +210,7 @@
   Chip NCR53C810, device id 0x1, revision id 0x2
   IO port address 0x6000, IRQ number 10
   Using memory mapped IO at virtual address 0x282c000
+  Synchronous transfer period 25, max commands per lun 4
 Profiling information:
   num_trans    = 18014
   num_kbytes   = 671314
@@ -175,7 +224,7 @@
   ms_post      = 1320
 -------------------------------------------------------
 
-General information is easy to understand. The device ID and the 
+General information is easy to understand. The device ID and the
 revision ID identify the SCSI chip as follows:
 
 Chip    Device id     Revision Id
@@ -187,15 +236,18 @@
 860       0x6
 825A      0x3            >= 0x10
 875       0xf
+895       0xc
 
 The profiling information is updated upon completion of SCSI commands.
-A data structure is allocated and zeroed when the host adapter is 
-attached. So, if the driver is a module, the profile counters are cleared each 
-time the driver is loaded.
-The "clearprof" command allows you to clear these counters at any time.
+A data structure is allocated and zeroed when the host adapter is
+attached. So, if the driver is a module, the profile counters are
+cleared each time the driver is loaded.  The "clearprof" command
+allows you to clear these counters at any time.
 
 The following counters are available:
-("num" prefix means "number of", "ms" means milli-seconds)
+
+("num" prefix means "number of",
+"ms" means milli-seconds)
 
 num_trans
 	Number of completed commands
@@ -238,46 +290,43 @@
 	(time from SCSI status get to command completion call)
 	Example above: 1.32 seconds spent for post processing
 
-Due to the 1/100 second tick of the system clock, "ms_post" time may be 
-wrong.
+Due to the 1/100 second tick of the system clock, "ms_post" time may
+be wrong.
 
-In the example above, we got 18038 interrupts "on the fly" and only 1673 script 
-breaks probably due to disconnections inside a segment of the scatter list. 
-This is an excellent result due to the fact that the driver tries to use small 
-data segments (512) for the scatter list. The CPU load of this rescatter process 
-is acceptable. Unlike other SCSI processors, NCR53C8XX controllers do not need  
-large data chunks in order to get better performance, and it seems that it 
-is just the opposite.
-The scatter/gather algorithm of the middle SCSI driver is not optimal for 
-NCR SCSI processors and should be tunable according to host type.
-
-You can tune the "wished" segment size for the scatterlist by changing the 
-following "define" in the file ncr53c8xx.h.
-Use only power of 2 greater than 512 (1024, 2048 or 4096).
-
-SCSI_NCR_SEGMENT_SIZE		(default: 512)
+In the example above, we got 18038 interrupts "on the fly" and only
+1673 script breaks generally due to disconnections inside a segment 
+of the scatter list.
 
 
 8. Control commands
 
-Control commands can be sent to the driver with write operations to the 
-proc SCSI file system. The generic command syntax is the following:
+Control commands can be sent to the driver with write operations to
+the proc SCSI file system. The generic command syntax is the
+following:
 
       echo "<verb> <parameters>" >/proc/scsi/ncr53c8xx/0
       (assumes controller number is 0)
 
+Using "all" for "<target>" parameter with the commands below will
+apply to all targets of the SCSI chain (except the controller).
+
 Available commands:
 
-8.1 Set minimum synchronous period
+8.1 Set minimum synchronous period factor
 
-    setsync <target> <period>
+    setsync <target> <period factor>
 
     target:    target number
-    period:    minimum synchronous period in nano-seconds.
-               Maximum speed = 1000/(4*period) MB/second
+    period:    minimum synchronous period.
+               Maximum speed = 1000/(4*period factor) except for special
+               cases below.
 
     Specify a period of 255, to force asynchronous transfer mode.
 
+      10 means 25 nano-seconds synchronous period
+      11 means 30 nano-seconds synchronous period
+      12 means 50 nano-seconds synchronous period
+
 8.2 Set wide size
 
     setwide <target> <size>
@@ -292,7 +341,6 @@
     target:    target number
     tags:      number of concurrent tagged commands
                must not be greater than SCSI_NCR_MAX_TAGS (default: 4)
-               must not be lower that 1 (see: known problems)
 
 8.4 Set order type for tagged command
 
@@ -321,23 +369,63 @@
 	nego:    print information about SCSI negotiations
 	phase:   print information on script interruptions
 
+    Use "setdebug" with no argument to reset debug flags.
+
 
 8.6 Clear profile counters
 
     clearprof
 
-    The profile counters are automatically cleared when the amount of data 
-    transfered reaches 1000 GB in order to avoid overflow.
+    The profile counters are automatically cleared when the amount of
+    data transfered reaches 1000 GB in order to avoid overflow.
     The "clearprof" command allows you to clear these counters at any time.
 
 
+8.7 Set flag (no_sync)
+ 
+    setflag <target> <flag>
+
+    target:    target number
+
+    For the moment, only one flag is available:
+
+        no_sync:   not allow target to disconnect.
+
+    Do not specify any flag in order to reset the flag. For example:
+    - setflag 4
+      will reset no_sync flag for target 4, so will allow it disconnections.
+    - setflag all
+      will allow disconnection for all devices on the SCSI bus.
+
+
+8.8 Debug error recovery
+
+    debug_error_recovery <error to trigger>
+
+    Available error type to trigger:
+        sge:     SCSI gross error
+        abort:   abort command from the middle-level driver
+        reset:   reset command from the middle-level driver
+        parity:  scsi parity detected in DATA IN phase
+        none:    restore driver normal behaviour
+
+    The code corresponding to this feature is normally not compiled.
+    Its purpose is driver testing only. In order to compile the code 
+    that allows to trigger error recovery you must define at compile time 
+    SCSI_NCR_DEBUG_ERROR_RECOVERY.
+    If you have compiled the driver with this option, nothing will happen 
+    as long as you donnot use the control command 'debug_error_recovery' 
+    with sge, abort, reset or parity as argument.
+    If you select an error type, it will be triggered by the driver every 
+    30 seconds.
+
 9. Configuration parameters
 
-If the firmware of all your devices is perfect enough, all the features 
-supported by the driver can be enabled at start-up.
-However, if only one has a flaw for some SCSI feature, you can disable the 
-support by the driver of this feature at linux start-up and enable this 
-feature after boot-up only for devices that support it safely.
+If the firmware of all your devices is perfect enough, all the
+features supported by the driver can be enabled at start-up.  However,
+if only one has a flaw for some SCSI feature, you can disable the
+support by the driver of this feature at linux start-up and enable
+this feature after boot-up only for devices that support it safely.
 
 CONFIG_SCSI_NCR53C8XX_IOMAPPED       (default answer: n)
     Answer "y" if you suspect your mother board to not allow memory mapped I/O.
@@ -347,9 +435,16 @@
     Answer "y" if you are sure that all your SCSI devices that are able to 
     accept tagged commands will proceed safely.
 
-CONFIG_SCSI_NCR53C8XX_FORCE_ASYNCHRONOUS (default answer: n)
-    This option forces asynchronous transfer mode for all SCSI devices. 
- 
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS         (default answer: 4)
+    This option allows you to specify the maximum number of tagged commands 
+    that can be queued to a device.
+
+CONFIG_SCSI_NCR53C8XX_SYNC            (default answer: 5)
+    This option allows you to specify the frequency in MHz the driver 
+    will use at boot time for synchronous data transfer negotiations.
+    This frequency can be changed later with the "setsync" control command.
+    0 means "asynchronous data transfers".
+
 CONFIG_SCSI_NCR53C8XX_FORCE_SYNC_NEGO (default answer: n)
     Force synchronous negotiation for all SCSI-2 devices.
     Some SCSI-2 devices do not report this feature in byte 7 of inquiry 
@@ -360,12 +455,331 @@
     you can answer "y". Then, all SCSI devices will never disconnect the bus 
     even while performing long SCSI operations.
 
-
-10. Some constants and flags of the ncr53c8xx.h header files
-
-Some of these are defined from the configuration parameters.
-To change other "defines", you must edit the header file.
-Do that only if you know what you are doing.
+CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
+    Genuine SYMBIOS boards use GPIO0 in output for controller LED and GPIO3 
+    bit as a flag indicating singled-ended/differential interface.
+    If all the boards of your system are genuine SYMBIOS boards or use
+    BIOS and drivers from SYMBIOS, you would want to enable this option.
+    This option must NOT be enabled if your system has at least one 53C8XX 
+    based scsi board with a vendor-specific BIOS.
+    For example, Tekram DC-390/U, DC-390/W and DC-390/F scsi controllers 
+    use a vendor-specific BIOS and are known to not use SYMBIOS compatible 
+    GPIO wiring. So, this option must not be enabled if your system has 
+    such a board installed.
+
+CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT
+    Enable support for reading the serial NVRAM data on Symbios and
+    some Symbios compatible cards, and Tekram DC390W/U/F cards. Useful for
+    systems with more than one Symbios compatible controller where at least
+    one has a serial NVRAM, or for a system with a mixture of Symbios and
+    Tekram cards. Enables setting the boot order of host adaptors
+    to something other than the default order or "reverse probe" order. 
+    Also enables Symbios and Tekram cards to be distinguished so
+    CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT may be set in a system with a
+    mixture of Symbios and Tekram cards so the Symbios cards can make use of
+    the full range of Symbios features, differential, led pin, without
+    causing problems for the Tekram card(s).
+
+10. Boot setup commands
+
+10.1 Syntax
+
+Setup commands can be passed to the driver at boot time.
+A boot setup command for the ncr53c8xx driver begins with the driver name 
+"ncr53c8xx=". The kernel syntax parser then expects an optionnal list of
+integers separated with comma followed by an optionnal list of  comma- 
+separated strings. Example of boot setup command under lilo prompt:
+
+lilo: linux root=/dev/hda2 ncr53c8xx=tags:4,sync:10,debug:0x200
+
+- enable tagged commands, up to 4 tagged commands queued.
+- set synchronous negotiation speed to 10 Mega-transfers / second.
+- set DEBUG_NEGO flag.
+
+For the moment, the integer list of arguments is disgarded by the driver. 
+It will be used in the future in order to allow a per controller setup.
+
+Each string argument must be specified as "keyword:value". Only lower-case 
+characters and digits are allowed.
+
+10.2 Available arguments
+
+Master parity checking
+      mpar:y     enabled
+      mpar:n     disabled
+
+Scsi parity checking
+      spar:y     enabled
+      spar:n     disabled
+
+Scsi disconnections
+      disc:y     enabled
+      disc:n     disabled
+ 
+Special features
+   Only apply to 810A, 825A, 860 and 875 controllers.
+   Have no effect with normal 810 and 825.
+      specf:y    enabled
+      specf:n    disabled
+
+Ultra SCSI support
+   Only apply to 860 and 875 controllers.
+   Have no effect with other ones.
+      ultra:y    enabled
+      ultra:n    disabled
+
+Number of tagged commands
+      tags:0     (or tags:1 ) tagged command queuing disabled
+      tags:#tags (#tags  > 1) tagged command queuing enabled
+  #tags will be truncated to the max queued commands configuration parameter.
+  If the driver is configured with a maximum of 4 queued commands, tags:4 is 
+  the right argument to specify.
+
+Default synchronous period factor
+      sync:255     disabled (asynchronous transfer mode)
+      sync:#factor
+  #factor = 10     Ultra-2 SCSI 40 Mega-transfers / second
+  #factor = 11     Ultra-2 SCSI 33 Mega-transfers / second
+  #factor < 25     Ultra   SCSI 20 Mega-transfers / second
+  #factor < 50     Fast    SCSI-2
+
+  In all cases, the driver will use the minimum transfer period supported by 
+  controllers according to NCR53C8XX chip type.
+
+Negotiate synchronous with all devices
+  (force sync nego)
+      fsn:y      enabled
+      fsn:n      disabled
+
+Verbosity level
+      verb:0     minimal
+      verb:1     normal
+      verb:2     too much
+
+Debug mode
+      debug:0	 clear debug flags
+      debug:#x   set debug flags
+  #x is an integer value combining the following power-of-2 values:
+  DEBUG_ALLOC       0x1
+  DEBUG_PHASE       0x2
+  DEBUG_POLL        0x4
+  DEBUG_QUEUE       0x8
+  DEBUG_RESULT     0x10
+  DEBUG_SCATTER    0x20
+  DEBUG_SCRIPT     0x40
+  DEBUG_TINY       0x80
+  DEBUG_TIMING    0x100
+  DEBUG_NEGO      0x200
+  DEBUG_TAGS      0x400
+  DEBUG_FREEZE    0x800
+  DEBUG_RESTART  0x1000
+
+  You can play safely with DEBUG_NEGO. However, some of these flags may 
+  generate bunches of syslog messages. 
+
+Burst max
+      burst:0    burst disabled
+      burst:255  get burst length from initial IO register settings.
+      burst:#x   burst enabled (1<<#x burst transfers max)
+  #x is an integer value which is log base 2 of the burst transfers max.
+  The NCR53C875 and NCR53C825A support up to 128 burst transfers (#x = 7).
+  Other chips only support up to 16 (#x = 4).
+  This is a maximum value. The driver set the burst length according to chip 
+  and revision ids. By default the driver uses the maximum value supported 
+  by the chip.
+
+LED support
+     led:1      enable  LED support
+     led:0      disable LED support
+  Donnot enable LED support if your scsi board does not use SDMS BIOS.
+  (See 'Configuration parameters')
+
+Max wide
+    wide:1      wide scsi enabled
+    wide:0      wide scsi disabled
+  Some scsi boards use a 875 (ultra wide) and only supply narrow connectors.
+  If you have connected a wide device with a 50 pins to 68 pins cable 
+  converter, any accepted wide negotiation will break further data transfers.
+  In such a case, using "wide:0" in the bootup command will be helpfull. 
+
+Differential mode
+    diff:0	never set up diff mode
+    diff:1	set up diff mode if BIOS set it
+    diff:2	always set up diff mode
+    diff:3	set diff mode if GPIO3 is not set
+
+IRQ mode
+    irqm:0	always open drain
+    irqm:1	same as initial settings (assumed BIOS settings)
+    irqm:2	always totem pole
+
+Reverse probe
+    revprob:n   probe chip ids from the PCI configuration in this order:
+                810, 815, 820, 860, 875, 885, 895, 896
+    revprob:y   probe chip ids in the reverse order.
+
+Fix up PCI configuration space
+    pcifix:<option bits>
+
+    Available option bits:
+        0x1:   Set PCI cache-line size register if not set.
+        0x2:   Set write and invalidate bit in PCI command register.
+        0x4:   Increase if necessary PCI latency timer according to burst max.
+
+    Use 'pcifix:7' in order to allow the driver to fix up all PCI features.
+
+Serial NVRAM
+    nvram:n     do not look for serial NVRAM
+    nvram:y     test controllers for onboard serial NVRAM
+
+Boot fail safe
+    safe:y	load the following assumed fail safe initial setup
+
+  master parity			disabled		mpar:n
+  scsi parity			enabled			spar:y
+  disconnections		not allowed		disc:n
+  special features		disabled		specf:n
+  ultra scsi			disabled		ultra:n
+  force sync negotiation	disabled		fsn:n
+  reverse probe			disabled		revprob:n
+  PCI fix up                    disabled                pcifix:0
+  serial NVRAM                  enabled                 nvram:y
+  verbosity level		2			verb:2
+  tagged command queuing	disabled		tags:0
+  synchronous negotiation	disabled		sync:255
+  debug flags			none			debug:0
+  burst length			from BIOS settings	burst:255
+  LED support			disabled		led:0
+  wide support			disabled		wide:0
+  settle time			10 seconds		settle:10
+  differential support		from BIOS settings	diff:1
+  irq mode			from BIOS settings	irqm:1
+
+10.3 Advised boot setup commands
+
+If the driver has been configured with default options, the equivalent 
+boot setup is:
+
+   ncr53c8xx=mpar:y,spar:y,disc:y,specf:y,fsn:n,ultra:y,fsn:n,revprob:n,verb:1\
+             tags:0,sync:50,debug:0,burst:7,led:0,wide:1,settle:2,diff:0,irqm:0
+
+For an installation diskette or a safe but not fast system,
+boot setup can be:
+
+    ncr53c8xx=safe:y,mpar:y,disc:y
+    ncr53c8xx=safe:y,disc:y
+    ncr53c8xx=safe:y,mpar:y
+    ncr53c8xx=safe:y
+
+My personnal system works flawlessly with the following equivalent setup:
+
+   ncr53c8xx=mpar:y,spar:y,disc:y,specf:y,fsn:n,ultra:y,fsn:n,revprob:n,verb:1\
+             tags:8,sync:12,debug:0,burst:7,led:1,wide:1,settle:2,diff:0,irqm:0
+
+The driver prints its actual setup when verbosity level is 2. You can try 
+"ncr53c8xx=verb:2" to get the "static" setup of the driver, or add "verb:2" 
+to your boot setup command in order to check the actual setup the driver is 
+using.
+
+10.4 PCI configuration fix-up boot option
+
+pcifix:<option bits>
+
+Available option bits:
+    0x1:     Set PCI cache-line size register if not set.
+    0x2:     Set write and invalidate bit in PCI command register.
+
+Use 'pcifix:3' in order to allow the driver to fix both PCI features.
+
+These options only apply to new SYMBIOS chips 810A, 825A, 860 and 875 
+and are only supported for Pentium and 486 class processors.
+Recent SYMBIOS 53C8XX scsi processors are able to use PCI read multiple 
+and PCI write and invalidate commands. These features require the 
+cache line size register to be properly set in the PCI configuration 
+space of the chips. On the other hand, chips will use PCI write and 
+invalidate commands only if the corresponding bit is set to 1 in the 
+PCI command register.
+
+Not all PCI bioses set the PCI cache line register and the PCI write and 
+invalidate bit in the PCI configuration space of 53C8XX chips.
+Optimized PCI accesses may be broken for some PCI/memory controllers or 
+make problems with some PCI boards.
+
+This fix-up works flawlessly on my system.
+(MB Triton HX / 53C875 / 53C810A)
+I use these options at my own risks as you will do if you decide to 
+use them too.
+
+
+10.5 Serial NVRAM support boot option
+
+nvram:n     do not look for serial NVRAM
+nvram:y     test controllers for onboard serial NVRAM
+
+This option is described below (see 17. Serial NVRAM support).
+When this option is enabled, the driver tries to detect all boards using 
+a Serial NVRAM. This memory is used to hold user set up parameters.
+
+The parameters the driver is able to get from the NVRAM depend on the 
+data format used, as follow:
+
+                                 Tekram format      Symbios format
+General and host parameters
+    Boot order                         N                   Y
+    Host SCSI ID                       Y                   Y
+    SCSI parity checking               Y                   Y
+    Verbose boot messages              N                   Y
+SCSI devices parameters
+    Synchronous transfer speed         Y                   Y
+    Wide 16 / Narrow                   Y                   Y
+    Tagged Command Queuing enabled     Y                   Y
+    Disconnections enabled             Y                   Y
+    Scan at boot time                  N                   Y
+
+In order to speed up the system boot, for each device configured without 
+the "scan at boot time" option, the driver forces an error on the 
+first TEST UNIT READY command received for this device.
+
+Some SDMS BIOS revisions seem to be unable to boot cleanly with very fast 
+hard disks. In such a situation you cannot configure the NVRAM with 
+optimized parameters value.
+
+The 'nvram' boot option can be entered in hexadecimal form in order 
+to ignore some options configured in the NVRAM, as follow:
+
+mvram=<bits options>
+      0x01   look for NVRAM  (equivalent to nvram=y)
+      0x02   ignore NVRAM "Synchronous negotiation" parameters for all devices
+      0x04   ignore NVRAM "Wide negotiation"  parameter for all devices
+      0x08   ignore NVRAM "Scan at boot time" parameter for all devices
+
+My Atlas Wide only boots cleanly in 8 bits asynchronous data transfer 
+mode. However, it works flawlessly at 20 MB/second with the driver.
+Using "nvram=0x7" allows me to boot in 8 bits/async and to let the driver 
+use its setup for synchronous and wide negotiations.
+
+
+11. Some constants and flags of the ncr53c8xx.h header file
+
+Some of these are defined from the configuration parameters.  To
+change other "defines", you must edit the header file.  Do that only
+if you know what you are doing.
+
+SCSI_NCR_SETUP_ULTRA_SUPPORT	(default: defined)
+	Ultra SCSI support.
+	Can be changed by the following boot setup command:
+		ncr53c8xx=ultra:n
+
+SCSI_NCR_SETUP_SPECIAL_FEATURES	(default: defined)
+	If defined, the driver will enable some special features according  
+	to chip and revision id.
+        For 810A, 860, 825A and 875 scsi chips, this option enables support 
+        of features that reduce load of PCI bus and memory accesses during  
+        scsi transfer processing: burst op-code fetch, read multiple, 
+        read line, prefetch, cache line line, write and invalidate, 
+        burst 128 (875 only), large dma fifo (875 only), offset 16 (875 only).
+	Can be changed by the following boot setup command:
+		ncr53c8xx=specf:n
 
 SCSI_NCR_IOMAPPED		(default: not defined)
 	If defined, normal I/O is forced.
@@ -377,26 +791,31 @@
 	Maximum number of simultaneous tagged commands to a device.
 	Can be changed by "settags <target> <maxtags>"
 
+SCSI_NCR_SETUP_DEFAULT_SYNC     (default: 50)
+	Transfer period factor the driver will use at boot time for synchronous 
+	negotiation. 0 means asynchronous.
+	Can be changed by "setsync <target> <period factor>"
+
+SCSI_NCR_SETUP_DEFAULT_TAGS     (default: 4)
+	Default number of simultaneous tagged commands to a device.
+	< 1 means tagged command queuing disabled at start-up.
+
 SCSI_NCR_ALWAYS_SIMPLE_TAG	(default: defined)
 	Use SIMPLE TAG for read and write commands.
 	Can be changed by "setorder <ordered|simple|default>"
 
-SCSI_NCR_TAGGED_QUEUE_DISABLED	(default: defined)
-	If defined, tagged command queuing is disable at start-up.
-	Can be changed by "settags <target> <maxtags>"
-
-SCSI_NCR_NO_DISCONNECT		(default: not defined)
-	If defined, targets are not allowed to disconnect.
+SCSI_NCR_SETUP_DISCONNECTION	(default: defined)
+	If defined, targets are allowed to disconnect.
 
-SCSI_NCR_FORCE_SYNC_NEGO	(default: not defined)
+SCSI_NCR_SETUP_FORCE_SYNC_NEGO	(default: not defined)
 	If defined, synchronous negotiation is tried for all SCSI-2 devices.
 	Can be changed by "setsync <target> <period>"
 
-SCSI_NCR_DISABLE_MPARITY_CHECK	(default: not defined)
-	If defined, master parity checking is disabled.
+SCSI_NCR_SETUP_MASTER_PARITY	(default: defined)
+	If defined, master parity checking is enabled.
 
-SCSI_NCR_DISABLE_PARITY_CHECK	(default: not defined)
-	If defined, SCSI parity checking is disabled.
+SCSI_NCR_SETUP_MASTER_PARITY	(default: defined)
+	If defined, SCSI parity checking is enabled.
 
 SCSI_NCR_PROFILE		(default: defined)
 	If defined, profiling information is gathered.
@@ -404,10 +823,6 @@
 SCSI_NCR_MAX_SCATTER		(default: 128)
 	Scatter list size of the driver ccb.
 
-SCSI_NCR_SEGMENT_SIZE		(default: 512)
-	If defined, the driver will try to use scatter segments of this size.
-	If not defined, the Linux scatter list is used as is.
-
 SCSI_NCR_MAX_TARGET		(default: 16)
 	Max number of targets per host.
 
@@ -435,49 +850,38 @@
 	Max number of LUNs per target.
 
 
-11. Provided files
+12. Installation
+
+12.1 Provided files
 
 Driver and common files:
 
 	README.ncr53c8xx	: this file
 	ChangeLog.ncr53c8xx	: change log
+	ConfigHelp.ncr53c8xx	: Part of Configure.help about the driver
 	ncr53c8xx.h		: definitions
 	ncr53c8xx.c		: the driver code
 	scsitag.c		: command tool to enable tagged queue
 	conf.modules		: sample of /etc/conf.modules
 
-Installation procedure 1 replacing the standard NCR53c7,8xx driver:
-
 	Install.ncr53c8xx	: installation script
-	Uninstall.ncr53c8xx	: uninstallation script
-	53c7,8xx.h		: included by hosts.c, override the standard driver
-
-	Patch-1.2.13.ncr53c8xx     : patch for linux-1.2.13
-	Patch-1.3.45-49.ncr53c8xx  : patch for linux-1.3.45 to linux-1.3.49
-	Patch-1.3.50-100.ncr53c8xx : patch for linux-1.3.50 to linux-1.3.100
-
-Installation procedure 2 adding the driver to the kernel tree:
 
-	Install2.ncr53c8xx	   : installation script
+	Patch-1.2.13.ncr53c8xx  : patch for linux-1.2.13
+	Patch-2.0.29.ncr53c8xx  : patch for linux-2.0.29
 
-	Patch2-2.0.0-1.ncr53c8xx   : patch for linux-2.0.0 and linux-2.0.1
-	Patch2-Current.ncr53c8xx   : patch used for sub-levels > 1
+You must untar the distribution with the following command:
 
-Prior to installing the driver, you must untar the distribution, as follow:
+	tar zxvf ncrBsd2Linux-2.2b-src.tar.gz
 
-	mkdir ncrB2L
-	cd ncrB2L
-	tar zxvf ncrBsd2Linux-1.12a-src.tar.gz
+The sub-directory ncr53c8xx-2.2b will be created. Change to this directory.
 
 
-12. Installation procedure for Linux version 1
+12.2 Installation procedure
 
-This install script only supports linux-1.2.13 and linux-1.3.45 to 1.3.100.
+This install script has been tested with linux-1.2.13 and 2.0.29.
 
-This procedure just moves the standard driver files to SAVE_53 sub-directory 
-of linux/drivers/scsi, copies the drivers file to that directory and patches 
-the SCSI Makefile.
-The standard driver can be restored with Uninstall.ncr53c8xx
+This procedure copies the new driver files to the kernel tree and
+applies a patch to some files of the kernel tree.
 
 	If your linux directory is at the standard location
 	"/usr/src/linux", just enter:
@@ -488,83 +892,546 @@
 
 	Make the kernel:
 		Change to linux source directory
-		Configure with 53c7,8xx support (Y or m)  for Install.ncr53c8xx
+		Configure with NCR53C7,8XX support = N
+		Configure with NCR53C8XX   support = Y (or m)
 		Make dependancies
 		Make the kernel (use make zdisk first)
 		Make and install modules if you have configured with 'm'
 
-	Notes:
-		Since release 1.3.90, additionnal configuation parameters 
-		have been added for the standard NCR driver.
-		Just reply Y or N as you want to these questions;
-		The NCR53C8XX driver ignores those parameters.
-
-	If you prefer the standard NCR driver of Linux:
-	just enter:
-		Uninstall.ncr53c8xx
-	or
-		Uninstall.ncr53c8xx <your_linux_directory>
-	if your linux root is not /usr/src/linux.
-
-
-13. Installation procedure for Linux version 2
-
-This procedure adds the driver to the kernel tree.
-Using "make config" you can choose between the standard driver and the BSD one.
-It is possible to configure both drivers as modules and to switch from one 
-to the other at run time.
-Take care to unload the current driver module before loading the other one.
 
-	If your linux directory is at the standard location
-	"/usr/src/linux", just enter:
-		Install2.ncr53c8xx
+13. Control commands under linux-1.2.13
 
-	Else enter:
-		Install2.ncr53c8xx <your_linux_directory>
-
-	Make the kernel:
-		Change to linux source directory
-		Configure with NCR53C8XX support (Y or m)
-		Make dependancies
-		Make the kernel (use make zdisk first)
-		Make and install modules if you have configured with 'm'
-
-
-14. Control commands under linux-1.2.13
-
-Profiling data and control commands using the proc SCSI file system are not 
-available for linux-1.2.13.
-The only control command available is "scsitag" which allows you to enable
-tagged command queuing support after linux boot-up.
+Profiling data and control commands using the proc SCSI file system
+are not available for linux-1.2.13.  The only control command
+available is "scsitag" which allows you to enable tagged command
+queuing support after linux boot-up.
 
 Tagged command queueing is disabled by default at system startup.
 
 You can enable tagged queue per device with the following command:
+
 	scsitag device_name (ex: scsitag /dev/sda)
 
 Use "cc -o scsitag scsitag.c" to create the "scsitag" executable.
 
 
-15. Known problems
+14. Known problems
 
-15.1 Tagged commands with Iomega Jaz device
+14.1 Tagged commands with Iomega Jaz device
 
-I have not tried this device, however it has been reported to me the following:
-This device is capable of Tagged command queuing. However while spinning up,
-it rejects Tagged commands. This behaviour is conforms to 6.8.2 of SCSI-2 
-specifications. The current behaviour of the driver in that situation is not 
-satisfying. So do not enable Tagged command queuing for devices that are able 
-to spin down.
-The other problem that may appear is timeouts. The only way to avoid timeouts 
-seems to edit linux/drivers/scsi/sd.c and to increase the current timeout 
-values.
-
-15.2 Tagged command queuing cannot be disabled at run time
-
-Once Tagged command queuing has been enabled, the driver will not allow you to 
-disable this feature ("settags <target> 0" is not supported).
-This problem is due to some limitations of the code added to the Linux version 
-of the driver.
+I have not tried this device, however it has been reported to me the
+following: This device is capable of Tagged command queuing. However
+while spinning up, it rejects Tagged commands. This behaviour is
+conforms to 6.8.2 of SCSI-2 specifications. The current behaviour of
+the driver in that situation is not satisfying. So do not enable
+Tagged command queuing for devices that are able to spin down.  The
+other problem that may appear is timeouts. The only way to avoid
+timeouts seems to edit linux/drivers/scsi/sd.c and to increase the
+current timeout values.
+
+14.2 Device names change when another controller is added.
+
+When you add a new NCR53C8XX chip based controller to a system that already 
+has one or more controllers of this family, it may happen that the order 
+the driver registers them to the kernel causes problems due to device 
+name changes.
+When at least one controller uses NvRAM, SDMS BIOS version 4 allows you to 
+define the order the BIOS will scan the scsi boards. The driver attaches 
+controllers according to BIOS information if NvRAM detect option is set.
+
+If your controllers do not have NvRAM, you can:
+
+- Ask the driver to probe chip ids in reverse order from the boot command
+  line: ncr53c8xx=revprob:y
+- Make appropriate changes in the fstab.
+- Use the 'scsidev' tool from Eric Youngdale.
+
+15. SCSI problem troubleshooting
+
+Most SCSI problems are due to a non conformant SCSI bus or to buggy
+devices.  If infortunately you have SCSI problems, you can check the
+following things:
+
+- SCSI bus cables
+- terminations at both end of the SCSI chain
+- linux syslog messages (some of them may help you)
+
+If you donnot find the source of problems, you can configure the
+driver with no features enabled.
+
+- only asynchronous data transfers
+- tagged commands disabled
+- disconnections not allowed
+
+Now, if your SCSI bus is ok, your system have every chance to work
+with this safe configuration but performances will not be optimal.
+
+If it still fails, then you can send your problem description to
+appropriate mailing lists or news-groups.  Send me a copy in order to
+be sure I will receive it.  Obviously, a bug in the driver code is
+possible.
+
+     My email address: Gerard Roudier <groudier@club-internet.fr>
+
+Allowing disconnections is important if you use several devices on
+your SCSI bus but often causes problems with buggy devices.
+Synchronous data transfers increases throughput of fast devices like
+hard disks.  Good SCSI hard disks with a large cache gain advantage of
+tagged commands queuing.
+
+Try to enable one feature at a time with control commands.  For example:
+
+- echo "setsync all 25" >/proc/scsi/ncr53c8xx/0
+  Will enable fast synchronous data transfer negotiation for all targets.
+
+- echo "setflag 3" >/proc/scsi/ncr53c8xx/0
+  Will reset flags (no_sync) for target 3, and so will allow it to disconnect 
+  the SCSI Bus.
+
+- echo "settags 3 4" >/proc/scsi/ncr53c8xx/0
+  Will enable tagged command queuing for target 3 if that device supports it.
+
+Once you have found the device and the feature that cause problems, just 
+disable that feature for that device.
+
+
+16. Synchonous transfer negotiation tables
+
+Tables below have been created by calling the routine the driver uses
+for synchronisation negotiation timing calculation and chip setting.
+The first table corresponds to Ultra chips 53875 and 53C860 with 80 MHz 
+clock and 5 clock divisors.
+The second one has been calculated by setting the scsi clock to 40 Mhz 
+and using 4 clock divisors and so applies to all NCR53C8XX chips in fast 
+SCSI-2 mode.
+
+Periods are in nano-seconds and speeds are in Mega-transfers per second.
+1 Mega-transfers/second means 1 MB/s with 8 bits SCSI and 2 MB/s with 
+Wide16 SCSI.
+
+16.1 Synchronous timings for 53C875 and 53C860 Ultra-SCSI controllers
+
+ ----------------------------------------------
+ Negotiated                     NCR settings
+ Factor   Period   Speed        Period   Speed
+ ------   ------   ------       ------   ------
+ 12       50       20.000       50       20.000
+ 13       52       19.230       62       16.000
+ 14       56       17.857       62       16.000
+ 15       60       16.666       62       16.000
+ 16       64       15.625       75       13.333
+ 17       68       14.705       75       13.333
+ 18       72       13.888       75       13.333
+ 19       76       13.157       87       11.428
+ 20       80       12.500       87       11.428
+ 21       84       11.904       87       11.428
+ 22       88       11.363       93       10.666
+ 23       92       10.869       93       10.666
+ 24       96       10.416      100       10.000
+ 25      100       10.000      100       10.000
+ 26      104        9.615      112        8.888
+ 27      108        9.259      112        8.888
+ 28      112        8.928      112        8.888
+ 29      116        8.620      125        8.000
+ 30      120        8.333      125        8.000
+ 31      124        8.064      125        8.000
+ 32      128        7.812      131        7.619
+ 33      132        7.575      150        6.666
+ 34      136        7.352      150        6.666
+ 35      140        7.142      150        6.666
+ 36      144        6.944      150        6.666
+ 37      148        6.756      150        6.666
+ 38      152        6.578      175        5.714
+ 39      156        6.410      175        5.714
+ 40      160        6.250      175        5.714
+ 41      164        6.097      175        5.714
+ 42      168        5.952      175        5.714
+ 43      172        5.813      175        5.714
+ 44      176        5.681      187        5.333
+ 45      180        5.555      187        5.333
+ 46      184        5.434      187        5.333
+ 47      188        5.319      200        5.000
+ 48      192        5.208      200        5.000
+ 49      196        5.102      200        5.000
+
+
+16.2 Synchronous timings for fast SCSI-2 53C8XX controllers
+
+ ----------------------------------------------
+ Negotiated                     NCR settings
+ Factor   Period   Speed        Period   Speed
+ ------   ------   ------       ------   ------
+ 25      100       10.000      100       10.000
+ 26      104        9.615      125        8.000
+ 27      108        9.259      125        8.000
+ 28      112        8.928      125        8.000
+ 29      116        8.620      125        8.000
+ 30      120        8.333      125        8.000
+ 31      124        8.064      125        8.000
+ 32      128        7.812      131        7.619
+ 33      132        7.575      150        6.666
+ 34      136        7.352      150        6.666
+ 35      140        7.142      150        6.666
+ 36      144        6.944      150        6.666
+ 37      148        6.756      150        6.666
+ 38      152        6.578      175        5.714
+ 39      156        6.410      175        5.714
+ 40      160        6.250      175        5.714
+ 41      164        6.097      175        5.714
+ 42      168        5.952      175        5.714
+ 43      172        5.813      175        5.714
+ 44      176        5.681      187        5.333
+ 45      180        5.555      187        5.333
+ 46      184        5.434      187        5.333
+ 47      188        5.319      200        5.000
+ 48      192        5.208      200        5.000
+ 49      196        5.102      200        5.000
+
+
+17. Serial NVRAM (added by Richard Waltham: dormouse@farsrobt.demon.co.uk)
+
+17.1 Features
+
+Enabling serial NVRAM support enables detection of the serial NVRAM included
+on Symbios and some Symbios compatible host adaptors, and Tekram boards. The 
+serial NVRAM is used by Symbios and Tekram to hold set up parameters for the 
+host adaptor and it's attached drives.
+
+The Symbios NVRAM also holds data on the boot order of host adaptors in a
+system with more than one host adaptor. This enables the order of scanning
+the cards for drives to be changed from the default used during host adaptor
+detection.
+
+This can be done to a limited extent at the moment using "reverse probe" but
+this only changes the order of detection of different types of cards. The
+NVRAM boot order settings can do this as well as change the order the same
+types of cards are scanned in, something "reverse probe" cannot do.
+
+Tekram boards using Symbios chips, DC390W/F/U, which have NVRAM are detected
+and this is used to distinguish between Symbios compatible and Tekram host 
+adaptors. This is used to disable the Symbios compatible "diff" setting
+incorrectly set on Tekram boards if the CONFIG_SCSI_53C8XX_SYMBIOS_COMPAT 
+configuration parameter is set enabling both Symbios and Tekram boards to be 
+used together with the Symbios cards using all their features, including
+"diff" support. ("led pin" support for Symbios compatible cards can remain
+enabled when using Tekram cards. It does nothing useful for Tekram host
+adaptors but does not cause problems either.)
+
+
+17.2 Symbios NVRAM layout
+
+typical data at NVRAM address 0x100 (53c810a NVRAM)
+-----------------------------------------------------------
+00 00
+64 01
+8e 0b
+
+00 30 00 00 00 00 07 00 00 00 00 00 00 00 07 04 10 04 00 00 
+
+04 00 0f 00 00 10 00 50 00 00 01 00 00 62 
+04 00 03 00 00 10 00 58 00 00 01 00 00 63 
+04 00 01 00 00 10 00 48 00 00 01 00 00 61 
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 
+
+0f 00 08 08 64 00 0a 00
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+
+00 00 00 00 00 00 00 00 
+00 00 00 00 00 00 00 00 
+00 00 00 00 00 00 00 00 
+00 00 00 00 00 00 00 00 
+00 00 00 00 00 00 00 00 
+00 00 00 00 00 00 00 00 
+00 00 00 00 00 00 00 00 
+00 00 00 00 00 00 00 00 
+
+00 00 00 00 00 00 00 00 
+00 00 00 00 00 00 00 00 
+00 00 00 00 00 00 00 00 
+00 00 00 00 00 00 00 00 
+00 00 00 00 00 00 00 00 
+00 00 00 00 00 00 00 00 
+00 00 00 00 00 00 00 00 
+00 00 00 00 00 00 00 00 
+
+00 00 00 00 00 00 00 00 
+00 00 00 00 00 00 00 00 
+00 00 00 00 00 00 00 00 
+
+fe fe
+00 00
+00 00
+-----------------------------------------------------------
+NVRAM layout details
+
+NVRAM Address 0x000-0x0ff not used
+              0x100-0x26f initialised data
+              0x270-0x7ff not used
+
+general layout
+
+        header  -   6 bytes,
+        data    - 356 bytes (checksum is byte sum of this data)
+        trailer -   6 bytes
+                  ---
+        total     368 bytes
+
+data area layout
+
+        controller set up  -  20 bytes
+        boot configuration -  56 bytes (4x14 bytes)
+        device set up      - 128 bytes (16x8 bytes)
+        unused (spare?)    - 152 bytes (19x8 bytes)
+                             ---
+        total                356 bytes
+
+-----------------------------------------------------------
+header
+
+00 00   - ?? start marker
+64 01   - byte count (lsb/msb excludes header/trailer)
+8e 0b   - checksum (lsb/msb excludes header/trailer)
+-----------------------------------------------------------
+controller set up
+
+00 30 00 00 00 00 07 00 00 00 00 00 00 00 07 04 10 04 00 00
+                   |     |                 |
+                   |     |                  -- host ID
+                   |      --flag bits 2
+                   |        0x00000001= scan order hi->low
+                   |            (default 0x00 - scan low->hi)
+                    --flag bits 1
+                       0x00000001 scam enable
+                       0x00000010 parity enable
+                       0x00000100 verbose boot msgs
+
+remaining bytes unknown - they do not appear to change in my
+current set up for any of the controllers.
+
+default set up is identical for 53c810a and 53c875 NVRAM
+-----------------------------------------------------------
+boot configuration
+
+boot order set by order of the devices in this table
+
+04 00 0f 00 00 10 00 50 00 00 01 00 00 62 -- 1st controller
+04 00 03 00 00 10 00 58 00 00 01 00 00 63    2nd controller
+04 00 01 00 00 10 00 48 00 00 01 00 00 61    3rd controller
+00 00 00 00 00 00 00 00 00 00 00 00 00 00    4th controller
+       |  |  |  |     |        |     |  |
+       |  |  |  |     |        |      ---- PCI io port adr
+       |  |  |  |     |         --0x01 init/scan at boot time
+       |  |  |  |      --PCI device/function number (0xdddddfff)
+       |  |   ----- ?? PCI vendor ID (lsb/msb)
+        ----PCI device ID (lsb/msb)
+
+?? use of this data is a guess but seems reasonable
+
+remaining bytes unknown - they do not appear to change in my
+current set up
+
+default set up is identical for 53c810a and 53c875 NVRAM
+-----------------------------------------------------------
+device set up (up to 16 devices - includes controller)
+
+0f 00 08 08 64 00 0a 00 - id 0
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 
+0f 00 08 08 64 00 0a 00 - id 15
+ |     |  |  |     |  |
+ |     |  |  |      ----timeout (lsb/msb)
+ |     |  |   --synch period (0x?? 40 Mtrans/sec- fast 40) (probably 0x28)
+ |     |  |                  (0x30 20 Mtrans/sec- fast 20)
+ |     |  |                  (0x64 10 Mtrans/sec- fast )
+ |     |  |                  (0xc8  5 Mtrans/sec)
+ |     |  |                  (0x00  asynchronous)
+ |     |   -- ?? max sync offset (0x08 in NVRAM on 53c810a) 
+ |     |                         (0x10 in NVRAM on 53c875)
+ |      --device bus width (0x08 narrow)
+ |                         (0x10 16 bit wide)
+  --flag bits
+    0x00000001 - disconnect enabled
+    0x00000010 - scan at boot time
+    0x00000100 - scan luns
+    0x00001000 - queue tags enabled
+
+remaining bytes unknown - they do not appear to change in my
+current set up
+
+?? use of this data is a guess but seems reasonable 
+(but it could be max bus width)
+
+default set up for 53c810a NVRAM
+default set up for 53c875 NVRAM - bus width     - 0x10
+                                - sync offset ? - 0x10
+                                - sync period   - 0x30
+-----------------------------------------------------------
+?? spare device space (32 bit bus ??)
+
+00 00 00 00 00 00 00 00  (19x8bytes)
+.
+.
+00 00 00 00 00 00 00 00
+
+default set up is identical for 53c810a and 53c875 NVRAM
+-----------------------------------------------------------
+trailer
+
+fe fe   - ? end marker ?
+00 00
+00 00
+
+default set up is identical for 53c810a and 53c875 NVRAM
+-----------------------------------------------------------
+
+
+
+17.3 Tekram NVRAM layout
+
+nvram 64x16 (1024 bit)
+
+Drive settings
+
+Drive ID 0-15 (addr 0x0yyyy0 = device setup, yyyy = ID)
+              (addr 0x0yyyy1 = 0x0000)
+
+    x x x x  x x x x  x x x x  x x x x
+               | | |      | |  | | | |
+               | | |      | |  | | |  ----- parity check   0 - off
+               | | |      | |  | | |                       1 - on
+               | | |      | |  | | |
+               | | |      | |  | |  ------- sync neg       0 - off
+               | | |      | |  | |                         1 - on
+               | | |      | |  | |
+               | | |      | |  |  --------- disconnect     0 - off
+               | | |      | |  |                           1 - on
+               | | |      | |  |
+               | | |      | |   ----------- start cmd      0 - off
+               | | |      | |                              1 - on
+               | | |      | |
+               | | |      |  -------------- tagged cmds    0 - off
+               | | |      |                                1 - on
+               | | |      | 
+               | | |       ---------------- wide neg       0 - off
+               | | |                                       1 - on
+               | | |
+                --------------------------- sync rate      0 - 10.0 Mtrans/sec
+                                                           1 -  8.0
+                                                           2 -  6.6
+                                                           3 -  5.7
+                                                           4 -  5.0
+                                                           5 -  4.0
+                                                           6 -  3.0
+                                                           7 -  2.0
+                                                           7 -  2.0
+                                                           8 - 20.0
+                                                           9 - 16.7
+                                                           a - 13.9
+                                                           b - 11.9
+
+Global settings
+
+Host flags 0 (addr 0x100000, 32) 
+
+    x x x x  x x x x  x x x x  x x x x
+    | | | |  | | | |           | | | |
+    | | | |  | | | |            ----------- host ID    0x00 - 0x0f
+    | | | |  | | | |
+    | | | |  | | |  ----------------------- support for    0 - off
+    | | | |  | | |                          > 2 drives     1 - on
+    | | | |  | | | 
+    | | | |  | |  ------------------------- support drives 0 - off
+    | | | |  | |                            > 1Gbytes      1 - on
+    | | | |  | |
+    | | | |  |  --------------------------- bus reset on   0 - off
+    | | | |  |                                power on     1 - on
+    | | | |  |
+    | | | |   ----------------------------- active neg     0 - off
+    | | | |                                                1 - on
+    | | | |
+    | | |  -------------------------------- imm seek       0 - off
+    | | |                                                  1 - on
+    | | |
+    | |  ---------------------------------- scan luns      0 - off
+    | |                                                    1 - on
+    | |
+     -------------------------------------- removable      0 - disable
+                                            as BIOS dev    1 - boot device
+                                                           2 - all
+
+Host flags 1 (addr 0x100001, 33)
+
+    x x x x  x x x x  x x x x  x x x x
+               | | |             | | | 
+               | | |              --------- boot delay     0 -   3 sec
+               | | |                                       1 -   5
+               | | |                                       2 -  10
+               | | |                                       3 -  20
+               | | |                                       4 -  30
+               | | |                                       5 -  60
+               | | |                                       6 - 120
+               | | |
+                --------------------------- max tag cmds   0 -  2
+                                                           1 -  4
+                                                           2 -  8
+                                                           3 - 16
+                                                           4 - 32
+
+Host flags 2 (addr 0x100010, 34)
+
+    x x x x  x x x x  x x x x  x x x x
+                                     |
+                                      ----- F2/F6 enable   0 - off ???
+                                                           1 - on  ???
+
+checksum (addr 0x111111)
+
+checksum = 0x1234 - (sum addr 0-63)
+
+----------------------------------------------------------------------------
+
+default nvram data:
+
+0x0037 0x0000 0x0037 0x0000 0x0037 0x0000 0x0037 0x0000
+0x0037 0x0000 0x0037 0x0000 0x0037 0x0000 0x0037 0x0000
+0x0037 0x0000 0x0037 0x0000 0x0037 0x0000 0x0037 0x0000
+0x0037 0x0000 0x0037 0x0000 0x0037 0x0000 0x0037 0x0000 
+
+0x0f07 0x0400 0x0001 0x0000 0x0000 0x0000 0x0000 0x0000
+0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
+0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000
+0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0xfbbc
 
 ===============================================================================
 End of NCR53C8XX driver README file
+
+
+
diff -urN linux-2.0.31-pre5/drivers/scsi/scsiiom.c linux-2.0.31-pre6/drivers/scsi/scsiiom.c
--- linux-2.0.31-pre5/drivers/scsi/scsiiom.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre6/drivers/scsi/scsiiom.c	2003-08-15 15:04:01.000000000 -0700
@@ -0,0 +1,1540 @@
+/***********************************************************************
+ *	FILE NAME : SCSIIOM.C					       *
+ *	     BY   : C.L. Huang,    ching@tekram.com.tw		       *
+ *	Description: Device Driver for Tekram DC-390 (T) PCI SCSI      *
+ *		     Bus Master Host Adapter			       *
+ ***********************************************************************/
+
+
+static USHORT
+DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
+{
+    USHORT ioport, rc;
+    UCHAR  bval, bval1, i, cnt;
+    PUCHAR ptr;
+    ULONG  wlval;
+
+    pSRB->TagNumber = 31;
+    ioport = pACB->IOPortBase;
+    bval = pDCB->UnitSCSIID;
+    outb(bval,ioport+Scsi_Dest_ID);
+    bval = pDCB->SyncPeriod;
+    outb(bval,ioport+Sync_Period);
+    bval = pDCB->SyncOffset;
+    outb(bval,ioport+Sync_Offset);
+    bval = pDCB->CtrlR1;
+    outb(bval,ioport+CtrlReg1);
+    bval = pDCB->CtrlR3;
+    outb(bval,ioport+CtrlReg3);
+    bval = pDCB->CtrlR4;
+    outb(bval,ioport+CtrlReg4);
+    bval = CLEAR_FIFO_CMD;	   /* Flush FIFO */
+    outb(bval,ioport+ScsiCmd);
+
+    pSRB->ScsiPhase = SCSI_NOP0;
+    bval = pDCB->IdentifyMsg;
+    if( !(pDCB->SyncMode & EN_ATN_STOP) )
+    {
+	if( (pSRB->CmdBlock[0] == INQUIRY) ||
+	    (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
+	    (pSRB->SRBFlag & AUTO_REQSENSE) )
+	{
+	    bval &= 0xBF;	/* NO disconnection */
+	    outb(bval,ioport+ScsiFifo);
+	    bval1 = SELECT_W_ATN;
+	    pSRB->SRBState = SRB_START_;
+	    if( pDCB->SyncMode & SYNC_ENABLE )
+	    {
+		if( !(pDCB->IdentifyMsg & 7) ||
+		    (pSRB->CmdBlock[0] != INQUIRY) )
+		{
+		    bval1 = SEL_W_ATN_STOP;
+		    pSRB->SRBState = SRB_MSGOUT;
+		}
+	    }
+	}
+	else
+	{
+	    if(pDCB->SyncMode & EN_TAG_QUEUING)
+	    {
+		outb(bval,ioport+ScsiFifo);
+		bval = MSG_SIMPLE_QTAG;
+		outb(bval,ioport+ScsiFifo);
+		wlval = 1;
+		bval = 0;
+		while( wlval & pDCB->TagMask )
+		{
+		    wlval = wlval << 1;
+		    bval++;
+		}
+		outb(bval,ioport+ScsiFifo);
+		pDCB->TagMask |= wlval;
+		pSRB->TagNumber = bval;
+		bval1 = SEL_W_ATN2;
+		pSRB->SRBState = SRB_START_;
+	    }
+	    else
+	    {
+		outb(bval,ioport+ScsiFifo);
+		bval1 = SELECT_W_ATN;
+		pSRB->SRBState = SRB_START_;
+	    }
+	}
+
+	if( pSRB->SRBFlag & AUTO_REQSENSE )
+	{
+	    bval = REQUEST_SENSE;
+	    outb(bval,ioport+ScsiFifo);
+	    bval = pDCB->IdentifyMsg << 5;
+	    outb(bval,ioport+ScsiFifo);
+	    bval = 0;
+	    outb(bval,ioport+ScsiFifo);
+	    outb(bval,ioport+ScsiFifo);
+	    bval = sizeof(pSRB->pcmd->sense_buffer);
+	    outb(bval,ioport+ScsiFifo);
+	    bval = 0;
+	    outb(bval,ioport+ScsiFifo);
+	}
+	else
+	{
+	    cnt = pSRB->ScsiCmdLen;
+	    ptr = (PUCHAR) pSRB->CmdBlock;
+	    for(i=0; i<cnt; i++)
+	    {
+		bval = *ptr++;
+		outb(bval,ioport+ScsiFifo);
+	    }
+	}
+    }
+    else	/* ATN_STOP */
+    {
+	if( (pSRB->CmdBlock[0] == INQUIRY) ||
+	    (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
+	    (pSRB->SRBFlag & AUTO_REQSENSE) )
+	{
+	    bval &= 0xBF;
+	    outb(bval,ioport+ScsiFifo);
+	    bval1 = SELECT_W_ATN;
+	    pSRB->SRBState = SRB_START_;
+	    if( pDCB->SyncMode & SYNC_ENABLE )
+	    {
+		if( !(pDCB->IdentifyMsg & 7) ||
+		    (pSRB->CmdBlock[0] != INQUIRY) )
+		{
+		    bval1 = SEL_W_ATN_STOP;
+		    pSRB->SRBState = SRB_MSGOUT;
+		}
+	    }
+	}
+	else
+	{
+	    if(pDCB->SyncMode & EN_TAG_QUEUING)
+	    {
+		outb(bval,ioport+ScsiFifo);
+		pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG;
+		wlval = 1;
+		bval = 0;
+		while( wlval & pDCB->TagMask )
+		{
+		    wlval = wlval << 1;
+		    bval++;
+		}
+		pDCB->TagMask |= wlval;
+		pSRB->TagNumber = bval;
+		pSRB->MsgOutBuf[1] = bval;
+		pSRB->MsgCnt = 2;
+		bval1 = SEL_W_ATN_STOP;
+		pSRB->SRBState = SRB_START_;
+	    }
+	    else
+	    {
+		outb(bval,ioport+ScsiFifo);
+		pSRB->MsgOutBuf[0] = MSG_NOP;
+		pSRB->MsgCnt = 1;
+		pSRB->SRBState = SRB_START_;
+		bval1 = SEL_W_ATN_STOP;
+	    }
+	}
+    }
+    bval = inb( ioport+Scsi_Status );
+    if( bval & INTERRUPT )
+    {
+	pSRB->SRBState = SRB_READY;
+	pDCB->TagMask &= ~( 1 << pSRB->TagNumber );
+	rc = 1;
+    }
+    else
+    {
+	pSRB->ScsiPhase = SCSI_NOP1;
+	pACB->pActiveDCB = pDCB;
+	pDCB->pActiveSRB = pSRB;
+	rc = 0;
+	outb(bval1,ioport+ScsiCmd);
+    }
+    return( rc );
+}
+
+
+#ifndef  VERSION_ELF_1_2_13
+static void
+DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
+#else
+static void
+DC390_Interrupt( int irq, struct pt_regs *regs)
+#endif
+{
+    PACB   pACB;
+    PDCB   pDCB;
+    PSRB   pSRB;
+    USHORT ioport = 0;
+    USHORT phase, i;
+    void   (*stateV)( PACB, PSRB, PUCHAR );
+    UCHAR  istate = 0;
+    UCHAR  sstatus=0, istatus;
+
+    pACB = pACB_start;
+    if( pACB == NULL )
+	return;
+    for( i=0; i < adapterCnt; i++ )
+    {
+	if( pACB->IRQLevel == (UCHAR) irq )
+	{
+	     ioport = pACB->IOPortBase;
+	     sstatus = inb( ioport+Scsi_Status );
+	     if( sstatus & INTERRUPT )
+		 break;
+	     else
+		pACB = pACB->pNextACB;
+	}
+	else
+	{
+	    pACB = pACB->pNextACB;
+	}
+    }
+
+#ifdef DC390_DEBUG1
+	printk("sstatus=%2x,",sstatus);
+#endif
+
+    if( pACB == (PACB )-1 )
+    {
+	printk("DC390: Spurious interrupt detected!\n");
+	return;
+    }
+
+    istate = inb( ioport+Intern_State );
+    istatus = inb( ioport+INT_Status );
+
+#ifdef DC390_DEBUG1
+	printk("Istatus=%2x,",istatus);
+#endif
+
+    if(istatus &  DISCONNECTED)
+    {
+	DC390_Disconnect( pACB );
+	return;
+    }
+
+    if(istatus &  RESELECTED)
+    {
+	DC390_Reselect( pACB );
+	return;
+    }
+
+    if(istatus &  INVALID_CMD)
+    {
+	DC390_InvalidCmd( pACB );
+	return;
+    }
+
+    if(istatus &  SCSI_RESET)
+    {
+	DC390_ScsiRstDetect( pACB );
+	return;
+    }
+
+    if( istatus & (SUCCESSFUL_OP+SERVICE_REQUEST) )
+    {
+	pDCB = pACB->pActiveDCB;
+	pSRB = pDCB->pActiveSRB;
+	if( pDCB )
+	{
+	    if( pDCB->DCBFlag & ABORT_DEV_ )
+		EnableMsgOut( pACB, pSRB );
+	}
+
+	phase = (USHORT) pSRB->ScsiPhase;
+	stateV = (void *) DC390_phase0[phase];
+	stateV( pACB, pSRB, &sstatus );
+
+	pSRB->ScsiPhase = sstatus & 7;
+	phase = (USHORT) sstatus & 7;
+	stateV = (void *) DC390_phase1[phase];
+	stateV( pACB, pSRB, &sstatus );
+    }
+}
+
+
+static void
+DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    UCHAR   sstatus, bval;
+    USHORT  ioport;
+    PSGL    psgl;
+    ULONG   ResidCnt, xferCnt;
+
+    ioport = pACB->IOPortBase;
+    sstatus = *psstatus;
+
+    if( !(pSRB->SRBState & SRB_XFERPAD) )
+    {
+	if( sstatus & PARITY_ERR )
+	    pSRB->SRBStatus |= PARITY_ERROR;
+
+	if( sstatus & COUNT_2_ZERO )
+	{
+	    bval = inb(ioport+DMA_Status);
+	    while( !(bval & DMA_XFER_DONE) )
+		bval = inb(ioport+DMA_Status);
+	    pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
+	    pSRB->SGIndex++;
+	    if( pSRB->SGIndex < pSRB->SGcount )
+	    {
+		pSRB->pSegmentList++;
+		psgl = pSRB->pSegmentList;
+
+#ifndef VERSION_ELF_1_2_13
+		pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+#else
+		pSRB->SGPhysAddr = (ULONG) psgl->address;
+#endif
+		pSRB->SGToBeXferLen = (ULONG) psgl->length;
+	    }
+	    else
+		pSRB->SGToBeXferLen = 0;
+	}
+	else
+	{
+	    bval = inb( ioport+Current_Fifo );
+	    bval &= 0x1f;
+	    ResidCnt = (ULONG) inb(ioport+CtcReg_High);
+	    ResidCnt = ResidCnt << 8;
+	    ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid);
+	    ResidCnt = ResidCnt << 8;
+	    ResidCnt |= (ULONG) inb(ioport+CtcReg_Low);
+	    ResidCnt += (ULONG) bval;
+
+	    xferCnt = pSRB->SGToBeXferLen - ResidCnt;
+	    pSRB->SGPhysAddr += xferCnt;
+	    pSRB->TotalXferredLen += xferCnt;
+	    pSRB->SGToBeXferLen = ResidCnt;
+	}
+    }
+    bval = WRITE_DIRECTION+DMA_IDLE_CMD;
+    outb( bval, ioport+DMA_Cmd);
+}
+
+static void
+DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    UCHAR   sstatus, bval;
+    USHORT  i, ioport, residual;
+    PSGL    psgl;
+    ULONG   ResidCnt, xferCnt;
+    PUCHAR  ptr;
+
+
+    ioport = pACB->IOPortBase;
+    sstatus = *psstatus;
+
+    if( !(pSRB->SRBState & SRB_XFERPAD) )
+    {
+	if( sstatus & PARITY_ERR )
+	    pSRB->SRBStatus |= PARITY_ERROR;
+
+	if( sstatus & COUNT_2_ZERO )
+	{
+	    bval = inb(ioport+DMA_Status);
+	    while( !(bval & DMA_XFER_DONE) )
+		bval = inb(ioport+DMA_Status);
+
+	    bval = READ_DIRECTION+DMA_IDLE_CMD;
+	    outb( bval, ioport+DMA_Cmd);
+
+	    pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
+	    pSRB->SGIndex++;
+	    if( pSRB->SGIndex < pSRB->SGcount )
+	    {
+		pSRB->pSegmentList++;
+		psgl = pSRB->pSegmentList;
+
+#ifndef VERSION_ELF_1_2_13
+		pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+#else
+		pSRB->SGPhysAddr = (ULONG) psgl->address;
+#endif
+		pSRB->SGToBeXferLen = (ULONG) psgl->length;
+	    }
+	    else
+		pSRB->SGToBeXferLen = 0;
+	}
+	else	/* phase changed */
+	{
+	    residual = 0;
+	    bval = inb(ioport+Current_Fifo);
+	    while( bval & 0x1f )
+	    {
+		if( (bval & 0x1f) == 1 )
+		{
+		    for(i=0; i< 0x100; i++)
+		    {
+			bval = inb(ioport+Current_Fifo);
+			if( !(bval & 0x1f) )
+			    goto din_1;
+			else if( i == 0x0ff )
+			{
+			    residual = 1;   /* ;1 residual byte */
+			    goto din_1;
+			}
+		    }
+		}
+		else
+		    bval = inb(ioport+Current_Fifo);
+	    }
+din_1:
+	    bval = READ_DIRECTION+DMA_BLAST_CMD;
+	    outb(bval, ioport+DMA_Cmd);
+	    for(i=0; i<0x8000; i++)
+	    {
+		bval = inb(ioport+DMA_Status);
+		if(bval & BLAST_COMPLETE)
+		    break;
+	    }
+	    bval = READ_DIRECTION+DMA_IDLE_CMD;
+	    outb(bval, ioport+DMA_Cmd);
+
+	    ResidCnt = (ULONG) inb(ioport+CtcReg_High);
+	    ResidCnt = ResidCnt << 8;
+	    ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid);
+	    ResidCnt = ResidCnt << 8;
+	    ResidCnt |= (ULONG) inb(ioport+CtcReg_Low);
+
+	    xferCnt = pSRB->SGToBeXferLen - ResidCnt;
+	    pSRB->SGPhysAddr += xferCnt;
+	    pSRB->TotalXferredLen += xferCnt;
+	    pSRB->SGToBeXferLen = ResidCnt;
+
+	    if( residual )
+	    {
+		bval = inb(ioport+ScsiFifo);	    /* get residual byte */
+#ifndef VERSION_ELF_1_2_13
+		ptr = (PUCHAR) phys_to_virt( pSRB->SGPhysAddr );
+#else
+		ptr = (PUCHAR) pSRB->SGPhysAddr;
+#endif
+		*ptr = bval;
+		pSRB->SGPhysAddr++;
+		pSRB->TotalXferredLen++;
+		pSRB->SGToBeXferLen--;
+	    }
+	}
+    }
+}
+
+static void
+DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+}
+
+static void
+DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    UCHAR  bval;
+    USHORT ioport;
+
+    ioport = pACB->IOPortBase;
+    bval = inb(ioport+ScsiFifo);
+    pSRB->TargetStatus = bval;
+    bval++;
+    bval = inb(ioport+ScsiFifo);	/* get message */
+    pSRB->EndMessage = bval;
+
+    *psstatus = SCSI_NOP0;
+    pSRB->SRBState = SRB_COMPLETED;
+    bval = MSG_ACCEPTED_CMD;
+    outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) )
+	*psstatus = SCSI_NOP0;
+}
+
+static void
+DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    UCHAR  bval;
+    USHORT ioport, wval, wval1;
+    PDCB   pDCB;
+    PSRB   psrb;
+
+    ioport = pACB->IOPortBase;
+    pDCB = pACB->pActiveDCB;
+
+    bval = inb( ioport+ScsiFifo );
+    if( !(pSRB->SRBState & SRB_MSGIN_MULTI) )
+    {
+	if(bval == MSG_DISCONNECT)
+	{
+	    pSRB->SRBState = SRB_DISCONNECT;
+	}
+	else if( bval == MSG_SAVE_PTR )
+	    goto  min6;
+	else if( (bval == MSG_EXTENDED) || ((bval >= MSG_SIMPLE_QTAG) &&
+					    (bval <= MSG_ORDER_QTAG)) )
+	{
+	    pSRB->SRBState |= SRB_MSGIN_MULTI;
+	    pSRB->MsgInBuf[0] = bval;
+	    pSRB->MsgCnt = 1;
+	    pSRB->pMsgPtr = &pSRB->MsgInBuf[1];
+	}
+	else if(bval == MSG_REJECT_)
+	{
+	    bval = RESET_ATN_CMD;
+	    outb(bval, ioport+ScsiCmd);
+	    if( pSRB->SRBState & DO_SYNC_NEGO)
+		goto  set_async;
+	}
+	else if( bval == MSG_RESTORE_PTR)
+	    goto  min6;
+	else
+	    goto  min6;
+    }
+    else
+    {	/* minx: */
+
+	*pSRB->pMsgPtr = bval;
+	pSRB->MsgCnt++;
+	pSRB->pMsgPtr++;
+	if( (pSRB->MsgInBuf[0] >= MSG_SIMPLE_QTAG) &&
+	    (pSRB->MsgInBuf[0] <= MSG_ORDER_QTAG) )
+	{
+	    if( pSRB->MsgCnt == 2)
+	    {
+		pSRB->SRBState = 0;
+		bval = pSRB->MsgInBuf[1];
+		pSRB = pDCB->pGoingSRB;
+		psrb = pDCB->pGoingLast;
+		if( pSRB )
+		{
+		    for( ;; )
+		    {
+			if(pSRB->TagNumber != bval)
+			{
+			    if( pSRB == psrb )
+				goto  mingx0;
+			    pSRB = pSRB->pNextSRB;
+			}
+			else
+			    break;
+		    }
+		    if( pDCB->DCBFlag & ABORT_DEV_ )
+		    {
+			pSRB->SRBState = SRB_ABORT_SENT;
+			EnableMsgOut( pACB, pSRB );
+		    }
+		    if( !(pSRB->SRBState & SRB_DISCONNECT) )
+			goto  mingx0;
+		    pDCB->pActiveSRB = pSRB;
+		    pSRB->SRBState = SRB_DATA_XFER;
+		}
+		else
+		{
+mingx0:
+		    pSRB = pACB->pTmpSRB;
+		    pSRB->SRBState = SRB_UNEXPECT_RESEL;
+		    pDCB->pActiveSRB = pSRB;
+		    pSRB->MsgOutBuf[0] = MSG_ABORT_TAG;
+		    EnableMsgOut2( pACB, pSRB );
+		}
+	    }
+	}
+	else if( (pSRB->MsgInBuf[0] == MSG_EXTENDED) && (pSRB->MsgCnt == 5) )
+	{
+	    pSRB->SRBState &= ~(SRB_MSGIN_MULTI+DO_SYNC_NEGO);
+	    if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != 1) )
+	    {	/* reject_msg: */
+		pSRB->MsgCnt = 1;
+		pSRB->MsgInBuf[0] = MSG_REJECT_;
+		bval = SET_ATN_CMD;
+		outb(bval, ioport+ScsiCmd);
+	    }
+	    else if( !(pSRB->MsgInBuf[3]) || !(pSRB->MsgInBuf[4]) )
+	    {
+set_async:
+		pDCB = pSRB->pSRBDCB;
+		pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE);
+		pDCB->SyncPeriod = 0;
+		pDCB->SyncOffset = 0;
+		pDCB->CtrlR3 = FAST_CLK;     /* ;non_fast */
+		pDCB->CtrlR4 &= 0x3f;
+		pDCB->CtrlR4 |= EATER_25NS;  /* ; 25ns glitch eater */
+		goto  re_prog;
+	    }
+	    else
+	    {	/* set_sync: */
+
+		pDCB = pSRB->pSRBDCB;
+		pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE;
+		pDCB->SyncOffset &= 0x0f0;
+		pDCB->SyncOffset |= pSRB->MsgInBuf[4];
+		pDCB->NegoPeriod = pSRB->MsgInBuf[3];
+		wval = (USHORT) pSRB->MsgInBuf[3];
+		wval = wval << 2;
+		wval--;
+		wval1 = wval / 25;
+		if( (wval1 * 25) != wval)
+		    wval1++;
+		bval = FAST_CLK+FAST_SCSI;
+		pDCB->CtrlR4 &= 0x3f;
+		if(wval1 >= 8)
+		{
+		    wval1--;
+		    bval = FAST_CLK;	    /* ;fast clock/normal scsi */
+		    pDCB->CtrlR4 |= EATER_25NS;   /* ;25 ns glitch eater */
+		}
+		pDCB->CtrlR3 = bval;
+		pDCB->SyncPeriod = (UCHAR)wval1;
+re_prog:
+		bval = pDCB->SyncPeriod;
+		outb(bval, ioport+Sync_Period);
+		bval = pDCB->SyncOffset;
+		outb(bval, ioport+Sync_Offset);
+		bval = pDCB->CtrlR3;
+		outb(bval, ioport+CtrlReg3);
+		bval = pDCB->CtrlR4;
+		outb(bval, ioport+CtrlReg4);
+		SetXferRate( pACB, pDCB);
+	    }
+	}
+    }
+min6:
+    *psstatus = SCSI_NOP0;
+    bval = MSG_ACCEPTED_CMD;
+    outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir)
+{
+    PSGL   psgl;
+    UCHAR  bval;
+    USHORT ioport;
+    ULONG  lval;
+
+
+    ioport = pACB->IOPortBase;
+    if( pSRB->SGIndex < pSRB->SGcount )
+    {
+	bval = DMA_IDLE_CMD | ioDir;   /* ;+EN_DMA_INT */
+	outb( bval, ioport+DMA_Cmd);
+	if( !pSRB->SGToBeXferLen )
+	{
+	    psgl = pSRB->pSegmentList;
+#ifndef VERSION_ELF_1_2_13
+	    pSRB->SGPhysAddr = virt_to_phys( psgl->address );
+#else
+	    pSRB->SGPhysAddr = (ULONG) psgl->address;
+#endif
+	    pSRB->SGToBeXferLen = (ULONG) psgl->length;
+	}
+	lval = pSRB->SGToBeXferLen;
+	bval = (UCHAR) lval;
+	outb(bval,ioport+CtcReg_Low);
+	lval = lval >> 8;
+	bval = (UCHAR) lval;
+	outb(bval,ioport+CtcReg_Mid);
+	lval = lval >> 8;
+	bval = (UCHAR) lval;
+	outb(bval,ioport+CtcReg_High);
+
+	lval = pSRB->SGToBeXferLen;
+	outl(lval, ioport+DMA_XferCnt);
+
+	lval = pSRB->SGPhysAddr;
+	outl( lval, ioport+DMA_XferAddr);
+
+	bval = DMA_COMMAND+INFO_XFER_CMD;
+	outb(bval, ioport+ScsiCmd);
+
+	pSRB->SRBState = SRB_DATA_XFER;
+
+	bval = DMA_IDLE_CMD | ioDir;	/* ;+EN_DMA_INT */
+	outb(bval, ioport+DMA_Cmd);
+
+	bval = DMA_START_CMD | ioDir;	/* ;+EN_DMA_INT */
+	outb(bval, ioport+DMA_Cmd);
+    }
+    else    /* xfer pad */
+    {
+	if( pSRB->SGcount )
+	{
+	    pSRB->AdaptStatus = H_OVER_UNDER_RUN;
+	    pSRB->SRBStatus |= OVER_RUN;
+	}
+	bval = 0;
+	outb(bval,ioport+CtcReg_Low);
+	outb(bval,ioport+CtcReg_Mid);
+	outb(bval,ioport+CtcReg_High);
+
+	pSRB->SRBState |= SRB_XFERPAD;
+	bval = DMA_COMMAND+XFER_PAD_BYTE;
+	outb(bval, ioport+ScsiCmd);
+/*
+	bval = DMA_IDLE_CMD | ioDir;	;+EN_DMA_INT
+	outb(bval, ioport+DMA_Cmd);
+	bval = DMA_START_CMD | ioDir;	;+EN_DMA_INT
+	outb(bval, ioport+DMA_Cmd);
+*/
+    }
+}
+
+
+static void
+DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    UCHAR  ioDir;
+
+    ioDir = WRITE_DIRECTION;
+    DataIO_Comm( pACB, pSRB, ioDir);
+}
+
+static void
+DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    UCHAR  ioDir;
+
+    ioDir = READ_DIRECTION;
+    DataIO_Comm( pACB, pSRB, ioDir);
+}
+
+static void
+DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    PDCB   pDCB;
+    UCHAR  bval;
+    PUCHAR ptr;
+    USHORT ioport, i,  cnt;
+
+
+    ioport = pACB->IOPortBase;
+    bval = RESET_ATN_CMD;
+    outb(bval, ioport+ScsiCmd);
+    bval = CLEAR_FIFO_CMD;
+    outb(bval, ioport+ScsiCmd);
+    if( !(pSRB->SRBFlag & AUTO_REQSENSE) )
+    {
+	cnt = (USHORT) pSRB->ScsiCmdLen;
+	ptr = (PUCHAR) pSRB->CmdBlock;
+	for(i=0; i < cnt; i++)
+	{
+	    outb(*ptr, ioport+ScsiFifo);
+	    ptr++;
+	}
+    }
+    else
+    {
+	bval = REQUEST_SENSE;
+	outb(bval, ioport+ScsiFifo);
+	pDCB = pACB->pActiveDCB;
+	bval = pDCB->IdentifyMsg << 5;
+	outb(bval, ioport+ScsiFifo);
+	bval = 0;
+	outb(bval, ioport+ScsiFifo);
+	outb(bval, ioport+ScsiFifo);
+	bval = sizeof(pSRB->pcmd->sense_buffer);
+	outb(bval, ioport+ScsiFifo);
+	bval = 0;
+	outb(bval, ioport+ScsiFifo);
+    }
+    pSRB->SRBState = SRB_COMMAND;
+    bval = INFO_XFER_CMD;
+    outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    UCHAR  bval;
+    USHORT ioport;
+
+    ioport = pACB->IOPortBase;
+    bval = CLEAR_FIFO_CMD;
+    outb(bval, ioport+ScsiCmd);
+    pSRB->SRBState = SRB_STATUS;
+    bval = INITIATOR_CMD_CMPLTE;
+    outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    UCHAR   bval;
+    USHORT  ioport, i, cnt;
+    PUCHAR  ptr;
+    PDCB    pDCB;
+
+    ioport = pACB->IOPortBase;
+    bval = CLEAR_FIFO_CMD;
+    outb(bval, ioport+ScsiCmd);
+    pDCB = pACB->pActiveDCB;
+    if( !(pSRB->SRBState & SRB_MSGOUT) )
+    {
+	cnt = pSRB->MsgCnt;
+	if( cnt )
+	{
+	    ptr = (PUCHAR) pSRB->MsgOutBuf;
+	    for(i=0; i < cnt; i++)
+	    {
+		outb(*ptr, ioport+ScsiFifo);
+		ptr++;
+	    }
+	    pSRB->MsgCnt = 0;
+	    if( (pDCB->DCBFlag & ABORT_DEV_) &&
+		(pSRB->MsgOutBuf[0] == MSG_ABORT) )
+		pSRB->SRBState = SRB_ABORT_SENT;
+	}
+	else
+	{
+	    bval = MSG_ABORT;	/* ??? MSG_NOP */
+	    if( (pSRB->CmdBlock[0] == INQUIRY ) ||
+		(pSRB->CmdBlock[0] == REQUEST_SENSE) ||
+		(pSRB->SRBFlag & AUTO_REQSENSE) )
+	    {
+		if( pDCB->SyncMode & SYNC_ENABLE )
+		    goto  mop1;
+	    }
+	    outb(bval, ioport+ScsiFifo);
+	}
+	bval = INFO_XFER_CMD;
+	outb( bval, ioport+ScsiCmd);
+    }
+    else
+    {
+mop1:
+	bval = MSG_EXTENDED;
+	outb(bval, ioport+ScsiFifo);
+	bval = 3;	/*    ;length of extended msg */
+	outb(bval, ioport+ScsiFifo);
+	bval = 1;	/*    ; sync nego */
+	outb(bval, ioport+ScsiFifo);
+	bval = pDCB->NegoPeriod;
+	outb(bval, ioport+ScsiFifo);
+	bval = SYNC_NEGO_OFFSET;
+	outb(bval, ioport+ScsiFifo);
+	pSRB->SRBState |= DO_SYNC_NEGO;
+	bval = INFO_XFER_CMD;
+	outb(bval, ioport+ScsiCmd);
+    }
+}
+
+static void
+DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    UCHAR  bval;
+    USHORT ioport;
+
+    ioport = pACB->IOPortBase;
+    bval = CLEAR_FIFO_CMD;
+    outb(bval, ioport+ScsiCmd);
+    if( !(pSRB->SRBState & SRB_MSGIN) )
+    {
+	pSRB->SRBState &= SRB_DISCONNECT;
+	pSRB->SRBState |= SRB_MSGIN;
+    }
+    bval = INFO_XFER_CMD;
+    outb(bval, ioport+ScsiCmd);
+}
+
+static void
+DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+}
+
+static void
+DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+}
+
+
+static void
+SetXferRate( PACB pACB, PDCB pDCB )
+{
+    UCHAR  bval;
+    USHORT cnt, i;
+    PDCB   ptr;
+
+    if( !(pDCB->IdentifyMsg & 0x07) )
+    {
+	if( pACB->scan_devices )
+	{
+	    CurrSyncOffset = pDCB->SyncOffset;
+	}
+	else
+	{
+	    ptr = pACB->pLinkDCB;
+	    cnt = pACB->DeviceCnt;
+	    bval = pDCB->UnitSCSIID;
+	    for(i=0; i<cnt; i++)
+	    {
+		if( ptr->UnitSCSIID == bval )
+		{
+		    ptr->SyncPeriod = pDCB->SyncPeriod;
+		    ptr->SyncOffset = pDCB->SyncOffset;
+		    ptr->CtrlR3 = pDCB->CtrlR3;
+		    ptr->CtrlR4 = pDCB->CtrlR4;
+		    ptr->SyncMode = pDCB->SyncMode;
+		}
+		ptr = ptr->pNextDCB;
+	    }
+	}
+    }
+    return;
+}
+
+
+static void
+DC390_Disconnect( PACB pACB )
+{
+    PDCB   pDCB;
+    PSRB   pSRB, psrb;
+    ULONG  flags;
+    USHORT ioport, i, cnt;
+    UCHAR  bval;
+
+#ifdef DC390_DEBUG0
+    printk("DISC,");
+#endif
+
+    save_flags(flags);
+    cli();
+    ioport = pACB->IOPortBase;
+    pDCB = pACB->pActiveDCB;
+    if (!pDCB)
+     {
+#ifdef DC390_DEBUG0
+	printk("ACB:%08lx->ActiveDCB:%08lx !,",(ULONG)pACB,(ULONG)pDCB);
+#endif
+	restore_flags(flags); return;
+     }
+    pSRB = pDCB->pActiveSRB;
+    pACB->pActiveDCB = 0;
+    pSRB->ScsiPhase = SCSI_NOP0;
+    bval = EN_SEL_RESEL;
+    outb(bval, ioport+ScsiCmd);
+    if( pSRB->SRBState & SRB_UNEXPECT_RESEL )
+    {
+	pSRB->SRBState = 0;
+	DoWaitingSRB( pACB );
+    }
+    else if( pSRB->SRBState & SRB_ABORT_SENT )
+    {
+	pDCB->TagMask = 0;
+	pDCB->DCBFlag = 0;
+	cnt = pDCB->GoingSRBCnt;
+	pDCB->GoingSRBCnt = 0;
+	pSRB = pDCB->pGoingSRB;
+	for( i=0; i < cnt; i++)
+	{
+	    psrb = pSRB->pNextSRB;
+	    pSRB->pNextSRB = pACB->pFreeSRB;
+	    pACB->pFreeSRB = pSRB;
+	    pSRB = psrb;
+	}
+	pDCB->pGoingSRB = 0;
+	DoWaitingSRB( pACB );
+    }
+    else
+    {
+	if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) ||
+	   !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) )
+	{	/* Selection time out */
+	    if( !(pACB->scan_devices) )
+	    {
+		pSRB->SRBState = SRB_READY;
+		RewaitSRB( pDCB, pSRB);
+	    }
+	    else
+	    {
+		pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT;
+		goto  disc1;
+	    }
+	}
+	else if( pSRB->SRBState & SRB_DISCONNECT )
+	{
+	    DoWaitingSRB( pACB );
+	}
+	else if( pSRB->SRBState & SRB_COMPLETED )
+	{
+disc1:
+	    if(pDCB->MaxCommand > 1)
+	    {
+	       bval = pSRB->TagNumber;
+	       pDCB->TagMask &= (~(1 << bval));   /* free tag mask */
+	    }
+	    pDCB->pActiveSRB = 0;
+	    pSRB->SRBState = SRB_FREE;
+	    SRBdone( pACB, pDCB, pSRB);
+	}
+    }
+    restore_flags(flags);
+    return;
+}
+
+
+static void
+DC390_Reselect( PACB pACB )
+{
+    PDCB   pDCB, pdcb;
+    PSRB   pSRB;
+    USHORT ioport, wval;
+    UCHAR  bval, bval1;
+
+
+#ifdef DC390_DEBUG0
+    printk("RSEL,");
+#endif
+    ioport = pACB->IOPortBase;
+    pDCB = pACB->pActiveDCB;
+    if( pDCB )
+    {	/* Arbitration lost but Reselection win */
+	pSRB = pDCB->pActiveSRB;
+	if( !( pACB->scan_devices ) )
+	{
+	    pSRB->SRBState = SRB_READY;
+	    RewaitSRB( pDCB, pSRB);
+	}
+    }
+    bval = inb(ioport+ScsiFifo);	/* get ID */
+    bval = bval ^ pACB->HostID_Bit;
+    wval = 0;
+    bval1 = 1;
+    for(;;)
+    {
+	if( !(bval & bval1) )
+	{
+	    bval1 = bval1 << 1;
+	    wval++;
+	}
+	else
+	    break;
+    }
+    wval |=  ( (USHORT) inb(ioport+ScsiFifo) & 7) << 8;  /* get LUN */
+    pDCB = pACB->pLinkDCB;
+    pdcb = pDCB;
+    while( wval != *((PUSHORT) &pDCB->UnitSCSIID) )
+    {
+	pDCB = pDCB->pNextDCB;
+	if( pDCB == pdcb )
+	    return;
+    }
+    pACB->pActiveDCB = pDCB;
+    if( pDCB->SyncMode & EN_TAG_QUEUING )
+    {
+	pSRB = pACB->pTmpSRB;
+	pDCB->pActiveSRB = pSRB;
+    }
+    else
+    {
+	pSRB = pDCB->pActiveSRB;
+	if( !pSRB || !(pSRB->SRBState & SRB_DISCONNECT) )
+	{
+	    pSRB= pACB->pTmpSRB;
+	    pSRB->SRBState = SRB_UNEXPECT_RESEL;
+	    pDCB->pActiveSRB = pSRB;
+	    EnableMsgOut( pACB, pSRB );
+	}
+	else
+	{
+	    if( pDCB->DCBFlag & ABORT_DEV_ )
+	    {
+		pSRB->SRBState = SRB_ABORT_SENT;
+		EnableMsgOut( pACB, pSRB );
+	    }
+	    else
+		pSRB->SRBState = SRB_DATA_XFER;
+	}
+    }
+    pSRB->ScsiPhase = SCSI_NOP0;
+    bval = pDCB->UnitSCSIID;
+    outb( bval, ioport+Scsi_Dest_ID);
+    bval = pDCB->SyncPeriod;
+    outb(bval, ioport+Sync_Period);
+    bval = pDCB->SyncOffset;
+    outb( bval, ioport+Sync_Offset);
+    bval = pDCB->CtrlR1;
+    outb(bval, ioport+CtrlReg1);
+    bval = pDCB->CtrlR3;
+    outb(bval, ioport+CtrlReg3);
+    bval = pDCB->CtrlR4;	/* ; Glitch eater */
+    outb(bval, ioport+CtrlReg4);
+    bval = MSG_ACCEPTED_CMD;	/* ;to rls the /ACK signal */
+    outb(bval, ioport+ScsiCmd);
+}
+
+
+static void
+SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
+{
+    PSRB   psrb;
+    UCHAR  bval, bval1, i, j, status;
+    PSCSICMD pcmd;
+    PSCSI_INQDATA  ptr;
+    USHORT disable_tag;
+    ULONG  flags;
+    PSGL   ptr2;
+    ULONG  swlval;
+
+    pcmd = pSRB->pcmd;
+    status = pSRB->TargetStatus;
+    if(pSRB->SRBFlag & AUTO_REQSENSE)
+    {
+	pSRB->SRBFlag &= ~AUTO_REQSENSE;
+	pSRB->AdaptStatus = 0;
+	pSRB->TargetStatus = SCSI_STAT_CHECKCOND;
+	if(status == SCSI_STAT_CHECKCOND)
+	{
+	    pcmd->result = DID_BAD_TARGET << 16;
+	    goto ckc_e;
+	}
+	if(pSRB->RetryCnt == 0)
+	{
+	    *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
+	    pSRB->TotalXferredLen = pSRB->Segment1[1];
+	    if( (pSRB->TotalXferredLen) &&
+		(pSRB->TotalXferredLen >= pcmd->underflow) )
+		pcmd->result |= (DID_OK << 16);
+	    else
+		pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
+				SCSI_STAT_CHECKCOND;
+#ifdef DC390_DEBUG0
+	printk("Cmd=%2x,Result=%8x,XferL=%8x,",pSRB->CmdBlock[0],
+		(UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);
+#endif
+	    goto ckc_e;
+	}
+	else
+	{
+	    pSRB->RetryCnt--;
+	    pSRB->AdaptStatus = 0;
+	    pSRB->TargetStatus = 0;
+	    *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
+	    *((PULONG) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1];
+	    if( pSRB->CmdBlock[0] == TEST_UNIT_READY )
+	    {
+		pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
+				SCSI_STAT_CHECKCOND;
+		goto ckc_e;
+	    }
+	    pcmd->result |= (DRIVER_SENSE << 24);
+	    pSRB->SGcount		 = (UCHAR) pSRB->Segment1[0];
+	    pSRB->ScsiCmdLen		 = (UCHAR) (pSRB->Segment1[0] >> 8);
+	    pSRB->SGIndex = 0;
+	    pSRB->TotalXferredLen = 0;
+	    pSRB->SGToBeXferLen = 0;
+	    if( pcmd->use_sg )
+		pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+	    else if( pcmd->request_buffer )
+	    {
+		pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+		pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+		pSRB->Segmentx.length = pcmd->request_bufflen;
+	    }
+	    if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
+		RewaitSRB( pDCB, pSRB );
+	    return;
+	}
+    }
+    if( status )
+    {
+	if( status == SCSI_STAT_CHECKCOND)
+	{
+	    if( (pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen) )
+	    {
+		bval = pSRB->SGcount;
+		swlval = 0;
+		ptr2 = pSRB->pSegmentList;
+		for( i=pSRB->SGIndex; i < bval; i++)
+		{
+		    swlval += ptr2->length;
+		    ptr2++;
+		}
+#ifdef	DC390_DEBUG0
+		printk("XferredLen=%8x,NotXferLen=%8x,",
+			(UINT) pSRB->TotalXferredLen, (UINT) swlval);
+#endif
+	    }
+	    RequestSense( pACB, pDCB, pSRB );
+	    return;
+	}
+	else if( status == SCSI_STAT_QUEUEFULL )
+	{
+	    bval = (UCHAR) pDCB->GoingSRBCnt;
+	    bval--;
+	    pDCB->MaxCommand = bval;
+	    RewaitSRB( pDCB, pSRB );
+	    pSRB->AdaptStatus = 0;
+	    pSRB->TargetStatus = 0;
+	    return;
+	}
+	else if(status == SCSI_STAT_SEL_TIMEOUT)
+	{
+	    pSRB->AdaptStatus = H_SEL_TIMEOUT;
+	    pSRB->TargetStatus = 0;
+	    pcmd->result = DID_BAD_TARGET << 16;
+	}
+	else
+	{
+	    pSRB->AdaptStatus = 0;
+	    if( pSRB->RetryCnt )
+	    {
+		pSRB->RetryCnt--;
+		pSRB->TargetStatus = 0;
+		pSRB->SGIndex = 0;
+		pSRB->TotalXferredLen = 0;
+		pSRB->SGToBeXferLen = 0;
+		if( pcmd->use_sg )
+		    pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+		else if( pcmd->request_buffer )
+		{
+		    pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+		    pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+		    pSRB->Segmentx.length = pcmd->request_bufflen;
+		}
+		if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
+		    RewaitSRB( pDCB, pSRB );
+		return;
+	    }
+	    else
+	    {
+		pcmd->result |= (DID_ERROR << 16) | (ULONG) (pSRB->EndMessage << 8) |
+			       (ULONG) status;
+	    }
+	}
+    }
+    else
+    {
+	status = pSRB->AdaptStatus;
+	if(status & H_OVER_UNDER_RUN)
+	{
+	    pSRB->TargetStatus = 0;
+	    pcmd->result |= (DID_OK << 16) | (pSRB->EndMessage << 8);
+	}
+	else if( pSRB->SRBStatus & PARITY_ERROR)
+	{
+	    pcmd->result |= (DID_PARITY << 16) | (pSRB->EndMessage << 8);
+	}
+	else		       /* No error */
+	{
+	    pSRB->AdaptStatus = 0;
+	    pSRB->TargetStatus = 0;
+	    pcmd->result |= (DID_OK << 16);
+	}
+    }
+
+ckc_e:
+    if( pACB->scan_devices )
+    {
+	if( pSRB->CmdBlock[0] == TEST_UNIT_READY )
+	{
+	    if(pcmd->result != (DID_OK << 16))
+	    {
+		if( pcmd->result & SCSI_STAT_CHECKCOND )
+		{
+		    goto RTN_OK;
+		}
+		else
+		{
+		    pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun);
+		    pPrevDCB->pNextDCB = pACB->pLinkDCB;
+		    if( (pcmd->target == pACB->max_id) &&
+		       ((pcmd->lun == 0) || (pcmd->lun == pACB->max_lun)) )
+		    {
+			pACB->scan_devices = 0;
+		    }
+		}
+	    }
+	    else
+	    {
+RTN_OK:
+		pPrevDCB->pNextDCB = pDCB;
+		pDCB->pNextDCB = pACB->pLinkDCB;
+		if( (pcmd->target == pACB->max_id) && (pcmd->lun == pACB->max_lun) )
+		    pACB->scan_devices = END_SCAN;
+	    }
+	}
+	else if( pSRB->CmdBlock[0] == INQUIRY )
+	{
+	    if( (pcmd->target == pACB->max_id) &&
+		(pcmd->lun == pACB->max_lun) )
+	    {
+		pACB->scan_devices = 0;
+	    }
+	    ptr = (PSCSI_INQDATA) (pcmd->request_buffer);
+	    if( pcmd->use_sg )
+		ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address);
+	    bval1 = ptr->DevType & SCSI_DEVTYPE;
+	    if(bval1 == SCSI_NODEV)
+	    {
+		pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun);
+		pPrevDCB->pNextDCB = pACB->pLinkDCB;
+	    }
+	    else
+	    {
+		pACB->DeviceCnt++;
+		pPrevDCB = pDCB;
+		pACB->pDCB_free = (PDCB) ((ULONG) (pACB->pDCB_free) + sizeof( DC390_DCB ));
+		pDCB->DevType = bval1;
+		if(bval1 == TYPE_DISK || bval1 == TYPE_MOD)
+		{
+		    if( (((ptr->Vers & 0x07) >= 2) || ((ptr->RDF & 0x0F) == 2)) &&
+			(ptr->Flags & SCSI_INQ_CMDQUEUE) &&
+			(pDCB->DevMode & TAG_QUEUING_) &&
+			(pDCB->DevMode & EN_DISCONNECT_) )
+		    {
+			disable_tag = 0;
+			for(i=0; i<BADDEVCNT; i++)
+			{
+			    for(j=0; j<28; j++)
+			    {
+				if( ((PUCHAR)ptr)[8+j] != baddevname1[i][j])
+				    break;
+			    }
+			    if(j == 28)
+			    {
+				disable_tag = 1;
+				break;
+			    }
+			}
+
+			if( !disable_tag )
+			{
+			    pDCB->MaxCommand = pACB->TagMaxNum;
+			    pDCB->SyncMode |= EN_TAG_QUEUING;
+			    pDCB->TagMask = 0;
+			}
+			else
+			{
+			    pDCB->SyncMode |= EN_ATN_STOP;
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+    save_flags( flags );
+    cli();
+/*  ReleaseSRB( pDCB, pSRB ); */
+
+    if(pSRB == pDCB->pGoingSRB )
+    {
+	pDCB->pGoingSRB = pSRB->pNextSRB;
+    }
+    else
+    {
+	psrb = pDCB->pGoingSRB;
+	while( psrb->pNextSRB != pSRB )
+	    psrb = psrb->pNextSRB;
+	psrb->pNextSRB = pSRB->pNextSRB;
+	if( pSRB == pDCB->pGoingLast )
+	    pDCB->pGoingLast = psrb;
+    }
+    pSRB->pNextSRB = pACB->pFreeSRB;
+    pACB->pFreeSRB = pSRB;
+    pDCB->GoingSRBCnt--;
+
+    DoWaitingSRB( pACB );
+    restore_flags(flags);
+
+/*  Notify cmd done */
+    pcmd->scsi_done( pcmd );
+
+    if( pDCB->QIORBCnt )
+	DoNextCmd( pACB, pDCB );
+    return;
+}
+
+
+static void
+DoingSRB_Done( PACB pACB )
+{
+    PDCB  pDCB, pdcb;
+    PSRB  psrb, psrb2;
+    USHORT  cnt, i;
+    PSCSICMD pcmd;
+
+    pDCB = pACB->pLinkDCB;
+    pdcb = pDCB;
+    do
+    {
+	cnt = pdcb->GoingSRBCnt;
+	psrb = pdcb->pGoingSRB;
+	for( i=0; i<cnt; i++)
+	{
+	    psrb2 = psrb->pNextSRB;
+	    pcmd = psrb->pcmd;
+	    pcmd->result = DID_RESET << 16;
+
+/*	    ReleaseSRB( pDCB, pSRB ); */
+
+	    psrb->pNextSRB = pACB->pFreeSRB;
+	    pACB->pFreeSRB = psrb;
+
+	    pcmd->scsi_done( pcmd );
+	    psrb  = psrb2;
+	}
+	pdcb->GoingSRBCnt = 0;;
+	pdcb->pGoingSRB = NULL;
+	pdcb->TagMask = 0;
+	pdcb = pdcb->pNextDCB;
+    }
+    while( pdcb != pDCB );
+}
+
+
+static void
+DC390_ResetSCSIBus( PACB pACB )
+{
+    USHORT ioport;
+    UCHAR  bval;
+    ULONG  flags;
+
+    save_flags(flags);
+    cli();
+    pACB->ACBFlag |= RESET_DEV;
+    ioport = pACB->IOPortBase;
+
+    bval = DMA_IDLE_CMD;
+    outb(bval,ioport+DMA_Cmd);
+
+    bval = RST_SCSI_BUS_CMD;
+    outb(bval,ioport+ScsiCmd);
+
+    restore_flags(flags);
+    return;
+}
+
+
+static void
+DC390_ScsiRstDetect( PACB pACB )
+{
+    ULONG wlval, flags;
+    USHORT ioport;
+    UCHAR  bval;
+
+#ifdef DC390_DEBUG0
+    printk("RST_DETEC");
+#endif
+    save_flags(flags);
+    sti();
+    wlval = jiffies + HZ;
+    while( jiffies < wlval );	 /* delay 1 sec */
+
+    cli();
+    ioport = pACB->IOPortBase;
+    bval = DMA_IDLE_CMD;
+    outb(bval,ioport+DMA_Cmd);
+    bval = CLEAR_FIFO_CMD;
+    outb(bval,ioport+ScsiCmd);
+
+    if( pACB->ACBFlag & RESET_DEV )
+	pACB->ACBFlag |= RESET_DONE;
+    else
+    {
+	pACB->ACBFlag |= RESET_DETECT;
+
+	ResetDevParam( pACB );
+/*	DoingSRB_Done( pACB ); ???? */
+	RecoverSRB( pACB );
+	pACB->pActiveDCB = NULL;
+	pACB->ACBFlag = 0;
+	DoWaitingSRB( pACB );
+    }
+    restore_flags(flags);
+    return;
+}
+
+
+static void
+RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB )
+{
+    PSCSICMD  pcmd;
+
+    pSRB->SRBFlag |= AUTO_REQSENSE;
+    pSRB->Segment0[0] = *((PULONG) &(pSRB->CmdBlock[0]));
+    pSRB->Segment0[1] = *((PULONG) &(pSRB->CmdBlock[4]));
+    pSRB->Segment1[0] = (ULONG) ((pSRB->ScsiCmdLen << 8) + pSRB->SGcount);
+    pSRB->Segment1[1] = pSRB->TotalXferredLen;
+    pSRB->AdaptStatus = 0;
+    pSRB->TargetStatus = 0;
+
+    pcmd = pSRB->pcmd;
+
+    pSRB->Segmentx.address = (PUCHAR) &(pcmd->sense_buffer);
+    pSRB->Segmentx.length = sizeof(pcmd->sense_buffer);
+    pSRB->pSegmentList = &pSRB->Segmentx;
+    pSRB->SGcount = 1;
+    pSRB->SGIndex = 0;
+
+    *((PULONG) &(pSRB->CmdBlock[0])) = 0x00000003;
+    pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5;
+    *((PUSHORT) &(pSRB->CmdBlock[4])) = sizeof(pcmd->sense_buffer);
+    pSRB->ScsiCmdLen = 6;
+
+    pSRB->TotalXferredLen = 0;
+    pSRB->SGToBeXferLen = 0;
+    if( DC390_StartSCSI( pACB, pDCB, pSRB ) )
+	RewaitSRB( pDCB, pSRB );
+}
+
+
+static void
+EnableMsgOut2( PACB pACB, PSRB pSRB )
+{
+    USHORT ioport;
+    UCHAR  bval;
+
+    ioport = pACB->IOPortBase;
+    pSRB->MsgCnt = 1;
+    bval = SET_ATN_CMD;
+    outb(bval, ioport+ScsiCmd);
+}
+
+
+static void
+EnableMsgOut( PACB pACB, PSRB pSRB )
+{
+    pSRB->MsgOutBuf[0] = MSG_ABORT;
+    EnableMsgOut2( pACB, pSRB );
+}
+
+
+static void
+DC390_InvalidCmd( PACB pACB )
+{
+   UCHAR bval;
+   USHORT ioport;
+   PSRB   pSRB;
+
+    pSRB = pACB->pActiveDCB->pActiveSRB;
+    if( pSRB->SRBState & (SRB_START_+SRB_MSGOUT) )
+    {
+	ioport = pACB->IOPortBase;
+	bval = CLEAR_FIFO_CMD;
+	outb(bval,(ioport+ScsiCmd));
+    }
+}
+
diff -urN linux-2.0.31-pre5/drivers/scsi/sd.c linux-2.0.31-pre6/drivers/scsi/sd.c
--- linux-2.0.31-pre5/drivers/scsi/sd.c	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/drivers/scsi/sd.c	2003-08-15 15:04:01.000000000 -0700
@@ -58,8 +58,8 @@
  *  Time out in seconds for disks and Magneto-opticals (which are slower).
  */
 
-#define SD_TIMEOUT (15 * HZ)
-#define SD_MOD_TIMEOUT (15 * HZ)
+#define SD_TIMEOUT (20 * HZ)
+#define SD_MOD_TIMEOUT (25 * HZ)
 
 #define CLUSTERABLE_DEVICE(SC) (SC->host->use_clustering && \
 				SC->device->type != TYPE_MOD)
diff -urN linux-2.0.31-pre5/drivers/scsi/tmscsim.c linux-2.0.31-pre6/drivers/scsi/tmscsim.c
--- linux-2.0.31-pre5/drivers/scsi/tmscsim.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre6/drivers/scsi/tmscsim.c	2003-08-15 15:04:01.000000000 -0700
@@ -0,0 +1,1928 @@
+/***********************************************************************
+ *	FILE NAME : TMSCSIM.C					       *
+ *	     BY   : C.L. Huang,  ching@tekram.com.tw		       *
+ *	Description: Device Driver for Tekram DC-390(T) PCI SCSI       *
+ *		     Bus Master Host Adapter			       *
+ * (C)Copyright 1995-1996 Tekram Technology Co., Ltd.		       *
+ ***********************************************************************/
+/*	Minor enhancements and bugfixes by				*
+ *	Kurt Garloff <K.Garloff@ping.de>				*
+ ***********************************************************************/
+/*	HISTORY:							*
+ *									*
+ *	REV#	DATE	NAME	DESCRIPTION				*
+ *	1.00  04/24/96	CLH	First release				*
+ *	1.01  06/12/96	CLH	Fixed bug of Media Change for Removable *
+ *				Device, scan all LUN. Support Pre2.0.10 *
+ *	1.02  06/18/96	CLH	Fixed bug of Command timeout ...	*
+ *	1.03  09/25/96	KG	Added tmscsim_proc_info()		*
+ *	1.04  10/11/96	CLH	Updating for support KV 2.0.x		*
+ *	1.05  10/18/96	KG	Fixed bug in DC390_abort(null ptr deref)*
+ *	1.06  10/25/96	KG	Fixed module support			*
+ *	1.07  11/09/96	KG	Fixed tmscsim_proc_info()		*
+ *	1.08  11/18/96	KG	Fixed null ptr in DC390_Disconnect()	*
+ *	1.09  11/30/96	KG	Added register the allocated IO space	*
+ *	1.10  12/05/96	CLH	Modified tmscsim_proc_info(), and reset *
+ *				pending interrupt in DC390_detect()	*
+ ***********************************************************************/
+
+
+#define DC390_DEBUG
+
+#define SCSI_MALLOC
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/delay.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/config.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < 66354 /* 1.3.50 */
+#include "../block/blk.h"
+#else
+#include <linux/blk.h>
+#endif
+
+#include "scsi.h"
+#include "hosts.h"
+#include "tmscsim.h"
+#include "constants.h"
+#include "sd.h"
+#include <linux/stat.h>
+
+#include "dc390.h"
+
+#define PCI_DEVICE_ID_AMD53C974 	PCI_DEVICE_ID_AMD_SCSI
+
+
+#ifndef  VERSION_ELF_1_2_13
+struct proc_dir_entry	proc_scsi_tmscsim ={
+       PROC_SCSI_DC390T, 7 ,"tmscsim",
+       S_IFDIR | S_IRUGO | S_IXUGO, 2
+       };
+#endif
+
+static USHORT DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB );
+static void DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+static void DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus);
+
+static void SetXferRate( PACB pACB, PDCB pDCB );
+static void DC390_Disconnect( PACB pACB );
+static void DC390_Reselect( PACB pACB );
+static void SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB );
+static void DoingSRB_Done( PACB pACB );
+static void DC390_ScsiRstDetect( PACB pACB );
+static void DC390_ResetSCSIBus( PACB pACB );
+static void RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );
+static void EnableMsgOut2( PACB pACB, PSRB pSRB );
+static void EnableMsgOut( PACB pACB, PSRB pSRB );
+static void DC390_InvalidCmd( PACB pACB );
+
+int    DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index );
+void   DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd );
+
+#ifdef MODULE
+static int DC390_release(struct Scsi_Host *host);
+static int DC390_shutdown (struct Scsi_Host *host);
+#endif
+
+
+static PSHT	pSHT_start = NULL;
+static PSH	pSH_start = NULL;
+static PSH	pSH_current = NULL;
+static PACB	pACB_start= NULL;
+static PACB	pACB_current = NULL;
+static PDCB	pPrevDCB = NULL;
+static USHORT	adapterCnt = 0;
+static USHORT	InitialTime = 0;
+static USHORT	CurrSyncOffset = 0;
+static ULONG	mech1addr;
+static UCHAR	mech2bus, mech2Agent, mech2CfgSPenR;
+
+static PVOID DC390_phase0[]={
+       DC390_DataOut_0,
+       DC390_DataIn_0,
+       DC390_Command_0,
+       DC390_Status_0,
+       DC390_Nop_0,
+       DC390_Nop_0,
+       DC390_MsgOut_0,
+       DC390_MsgIn_0,
+       DC390_Nop_1
+       };
+
+static PVOID DC390_phase1[]={
+       DC390_DataOutPhase,
+       DC390_DataInPhase,
+       DC390_CommandPhase,
+       DC390_StatusPhase,
+       DC390_Nop_0,
+       DC390_Nop_0,
+       DC390_MsgOutPhase,
+       DC390_MsgInPhase,
+       DC390_Nop_1,
+       };
+
+UCHAR  eepromBuf[MAX_ADAPTER_NUM][128];
+
+
+UCHAR  clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20};
+
+UCHAR  baddevname1[2][28] ={
+       "SEAGATE ST3390N         9546",
+       "HP      C3323-300       4269"};
+
+#define BADDEVCNT	2
+
+
+/***********************************************************************
+ *
+ *
+ *
+ **********************************************************************/
+static void
+QLinkcmd( PSCSICMD cmd, PDCB pDCB )
+{
+    ULONG  flags;
+    PSCSICMD  pcmd;
+
+    save_flags(flags);
+    cli();
+
+    if( !pDCB->QIORBCnt )
+    {
+	pDCB->pQIORBhead = cmd;
+	pDCB->pQIORBtail = cmd;
+	pDCB->QIORBCnt++;
+	cmd->next = NULL;
+    }
+    else
+    {
+	pcmd = pDCB->pQIORBtail;
+	pcmd->next = cmd;
+	pDCB->pQIORBtail = cmd;
+	pDCB->QIORBCnt++;
+	cmd->next = NULL;
+    }
+
+    restore_flags(flags);
+}
+
+
+static PSCSICMD
+Getcmd( PDCB pDCB )
+{
+    ULONG  flags;
+    PSCSICMD  pcmd;
+
+    save_flags(flags);
+    cli();
+
+    pcmd = pDCB->pQIORBhead;
+    pDCB->pQIORBhead = pcmd->next;
+    pcmd->next = NULL;
+    pDCB->QIORBCnt--;
+
+    restore_flags(flags);
+    return( pcmd );
+}
+
+
+static PSRB
+GetSRB( PACB pACB )
+{
+    ULONG  flags;
+    PSRB   pSRB;
+
+    save_flags(flags);
+    cli();
+
+    pSRB = pACB->pFreeSRB;
+    if( pSRB )
+    {
+	pACB->pFreeSRB = pSRB->pNextSRB;
+	pSRB->pNextSRB = NULL;
+    }
+    restore_flags(flags);
+    return( pSRB );
+}
+
+
+static void
+RewaitSRB0( PDCB pDCB, PSRB pSRB )
+{
+    PSRB   psrb1;
+    ULONG  flags;
+
+    save_flags(flags);
+    cli();
+
+    if( (psrb1 = pDCB->pWaitingSRB) )
+    {
+	pSRB->pNextSRB = psrb1;
+	pDCB->pWaitingSRB = pSRB;
+    }
+    else
+    {
+	pSRB->pNextSRB = NULL;
+	pDCB->pWaitingSRB = pSRB;
+	pDCB->pWaitLast = pSRB;
+    }
+    restore_flags(flags);
+}
+
+
+static void
+RewaitSRB( PDCB pDCB, PSRB pSRB )
+{
+    PSRB   psrb1;
+    ULONG  flags;
+    UCHAR  bval;
+
+    save_flags(flags);
+    cli();
+    pDCB->GoingSRBCnt--;
+    psrb1 = pDCB->pGoingSRB;
+    if( pSRB == psrb1 )
+    {
+	pDCB->pGoingSRB = psrb1->pNextSRB;
+    }
+    else
+    {
+	while( pSRB != psrb1->pNextSRB )
+	    psrb1 = psrb1->pNextSRB;
+	psrb1->pNextSRB = pSRB->pNextSRB;
+	if( pSRB == pDCB->pGoingLast )
+	    pDCB->pGoingLast = psrb1;
+    }
+    if( (psrb1 = pDCB->pWaitingSRB) )
+    {
+	pSRB->pNextSRB = psrb1;
+	pDCB->pWaitingSRB = pSRB;
+    }
+    else
+    {
+	pSRB->pNextSRB = NULL;
+	pDCB->pWaitingSRB = pSRB;
+	pDCB->pWaitLast = pSRB;
+    }
+
+    bval = pSRB->TagNumber;
+    pDCB->TagMask &= (~(1 << bval));	  /* Free TAG number */
+    restore_flags(flags);
+}
+
+
+static void
+DoWaitingSRB( PACB pACB )
+{
+    ULONG  flags;
+    PDCB   ptr, ptr1;
+    PSRB   pSRB;
+
+    save_flags(flags);
+    cli();
+
+    if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) )
+    {
+	ptr = pACB->pDCBRunRobin;
+	if( !ptr )
+	{
+	    ptr = pACB->pLinkDCB;
+	    pACB->pDCBRunRobin = ptr;
+	}
+	ptr1 = ptr;
+	for( ;ptr1; )
+	{
+	    pACB->pDCBRunRobin = ptr1->pNextDCB;
+	    if( !( ptr1->MaxCommand > ptr1->GoingSRBCnt ) ||
+		!( pSRB = ptr1->pWaitingSRB ) )
+	    {
+		if(pACB->pDCBRunRobin == ptr)
+		    break;
+		ptr1 = ptr1->pNextDCB;
+	    }
+	    else
+	    {
+		if( !DC390_StartSCSI(pACB, ptr1, pSRB) )
+		{
+		    ptr1->GoingSRBCnt++;
+		    if( ptr1->pWaitLast == pSRB )
+		    {
+			ptr1->pWaitingSRB = NULL;
+			ptr1->pWaitLast = NULL;
+		    }
+		    else
+		    {
+			ptr1->pWaitingSRB = pSRB->pNextSRB;
+		    }
+		    pSRB->pNextSRB = NULL;
+
+		    if( ptr1->pGoingSRB )
+			ptr1->pGoingLast->pNextSRB = pSRB;
+		    else
+			ptr1->pGoingSRB = pSRB;
+		    ptr1->pGoingLast = pSRB;
+		}
+		break;
+	    }
+	}
+    }
+    restore_flags(flags);
+    return;
+}
+
+
+static void
+SRBwaiting( PDCB pDCB, PSRB pSRB)
+{
+    if( pDCB->pWaitingSRB )
+    {
+	pDCB->pWaitLast->pNextSRB = pSRB;
+	pDCB->pWaitLast = pSRB;
+	pSRB->pNextSRB = NULL;
+    }
+    else
+    {
+	pDCB->pWaitingSRB = pSRB;
+	pDCB->pWaitLast = pSRB;
+    }
+}
+
+
+static void
+SendSRB( PSCSICMD pcmd, PACB pACB, PSRB pSRB )
+{
+    ULONG  flags;
+    PDCB   pDCB;
+
+    save_flags(flags);
+    cli();
+
+    pDCB = pSRB->pSRBDCB;
+    if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) ||
+	(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) )
+    {
+	SRBwaiting(pDCB, pSRB);
+	goto SND_EXIT;
+    }
+
+    if( pDCB->pWaitingSRB )
+    {
+	SRBwaiting(pDCB, pSRB);
+/*	pSRB = GetWaitingSRB(pDCB); */
+	pSRB = pDCB->pWaitingSRB;
+	pDCB->pWaitingSRB = pSRB->pNextSRB;
+	pSRB->pNextSRB = NULL;
+    }
+
+    if( !DC390_StartSCSI(pACB, pDCB, pSRB) )
+    {
+	pDCB->GoingSRBCnt++;
+	if( pDCB->pGoingSRB )
+	{
+	    pDCB->pGoingLast->pNextSRB = pSRB;
+	    pDCB->pGoingLast = pSRB;
+	}
+	else
+	{
+	    pDCB->pGoingSRB = pSRB;
+	    pDCB->pGoingLast = pSRB;
+	}
+    }
+    else
+	RewaitSRB0( pDCB, pSRB );
+
+SND_EXIT:
+    restore_flags(flags);
+    return;
+}
+
+
+/***********************************************************************
+ * Function : static int DC390_queue_command (Scsi_Cmnd *cmd,
+ *					       void (*done)(Scsi_Cmnd *))
+ *
+ * Purpose : enqueues a SCSI command
+ *
+ * Inputs : cmd - SCSI command, done - function called on completion, with
+ *	    a pointer to the command descriptor.
+ *
+ * Returns : 0
+ *
+ ***********************************************************************/
+
+int
+DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
+{
+    USHORT ioport, i;
+    Scsi_Cmnd *pcmd;
+    struct Scsi_Host *psh;
+    PACB   pACB;
+    PDCB   pDCB;
+    PSRB   pSRB;
+    ULONG  flags;
+    PUCHAR ptr,ptr1;
+
+    psh = cmd->host;
+    pACB = (PACB ) psh->hostdata;
+    ioport = pACB->IOPortBase;
+
+#ifdef DC390_DEBUG0
+/*  if(pACB->scan_devices) */
+	printk("Cmd=%2x,ID=%d,LUN=%d,",cmd->cmnd[0],cmd->target,cmd->lun);
+#endif
+
+    if( (pACB->scan_devices == END_SCAN) && (cmd->cmnd[0] != INQUIRY) )
+    {
+	pACB->scan_devices = 0;
+	pPrevDCB->pNextDCB = pACB->pLinkDCB;
+    }
+    else if( (pACB->scan_devices) && (cmd->cmnd[0] == 8) )
+    {
+	pACB->scan_devices = 0;
+	pPrevDCB->pNextDCB = pACB->pLinkDCB;
+    }
+
+    if ( ( cmd->target > pACB->max_id ) || (cmd->lun > pACB->max_lun) )
+    {
+/*	printk("DC390: Ignore target %d lun %d\n",
+		cmd->target, cmd->lun); */
+	cmd->result = (DID_BAD_TARGET << 16);
+	done(cmd);
+	return( 0 );
+    }
+
+    if( (pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
+    {
+	if( pACB->DeviceCnt < MAX_DEVICES )
+	{
+	    pACB->DCBmap[cmd->target] |= (1 << cmd->lun);
+	    pDCB = pACB->pDCB_free;
+#ifdef DC390_DEBUG0
+	    printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);
+#endif
+	    DC390_initDCB( pACB, pDCB, cmd );
+	}
+	else	/* ???? */
+	{
+/*	    printk("DC390: Ignore target %d lun %d\n",
+		    cmd->target, cmd->lun); */
+	    cmd->result = (DID_BAD_TARGET << 16);
+	    done(cmd);
+	    return(0);
+	}
+    }
+    else if( !(pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
+    {
+/*	printk("DC390: Ignore target %d lun %d\n",
+		cmd->target, cmd->lun); */
+	cmd->result = (DID_BAD_TARGET << 16);
+	done(cmd);
+	return(0);
+    }
+    else
+    {
+	pDCB = pACB->pLinkDCB;
+	while( (pDCB->UnitSCSIID != cmd->target) ||
+	       (pDCB->UnitSCSILUN != cmd->lun) )
+	{
+	    pDCB = pDCB->pNextDCB;
+	}
+#ifdef DC390_DEBUG0
+	    printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target);
+#endif
+    }
+
+    cmd->scsi_done = done;
+    cmd->result = 0;
+
+    save_flags(flags);
+    cli();
+
+    if( pDCB->QIORBCnt )
+    {
+	QLinkcmd( cmd, pDCB );
+	pcmd = Getcmd( pDCB );
+    }
+    else
+	pcmd = cmd;
+
+    pSRB = GetSRB( pACB );
+
+    if( !pSRB )
+    {
+	QLinkcmd( pcmd, pDCB );
+	restore_flags(flags);
+	return(0);
+    }
+
+/*  BuildSRB(pSRB); */
+
+    pSRB->pSRBDCB = pDCB;
+    pSRB->pcmd = pcmd;
+    ptr = (PUCHAR) pSRB->CmdBlock;
+    ptr1 = (PUCHAR) pcmd->cmnd;
+    pSRB->ScsiCmdLen = pcmd->cmd_len;
+    for(i=0; i< pcmd->cmd_len; i++)
+    {
+	*ptr = *ptr1;
+	ptr++;
+	ptr1++;
+    }
+    if( pcmd->use_sg )
+    {
+	pSRB->SGcount = (UCHAR) pcmd->use_sg;
+	pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+    }
+    else if( pcmd->request_buffer )
+    {
+	pSRB->SGcount = 1;
+	pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+	pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+	pSRB->Segmentx.length = pcmd->request_bufflen;
+    }
+    else
+	pSRB->SGcount = 0;
+
+    pSRB->SGIndex = 0;
+    pSRB->AdaptStatus = 0;
+    pSRB->TargetStatus = 0;
+    pSRB->MsgCnt = 0;
+    if( pDCB->DevType != TYPE_TAPE )
+	pSRB->RetryCnt = 1;
+    else
+	pSRB->RetryCnt = 0;
+    pSRB->SRBStatus = 0;
+    pSRB->SRBFlag = 0;
+    pSRB->SRBState = 0;
+    pSRB->TotalXferredLen = 0;
+    pSRB->SGPhysAddr = 0;
+    pSRB->SGToBeXferLen = 0;
+    pSRB->ScsiPhase = 0;
+    pSRB->EndMessage = 0;
+    SendSRB( pcmd, pACB, pSRB );
+
+    restore_flags(flags);
+    return(0);
+}
+
+
+static void
+DoNextCmd( PACB pACB, PDCB pDCB )
+{
+    Scsi_Cmnd *pcmd;
+    PSRB   pSRB;
+    ULONG  flags;
+    PUCHAR ptr,ptr1;
+    USHORT i;
+
+
+    if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) )
+	return;
+    save_flags(flags);
+    cli();
+
+    pcmd = Getcmd( pDCB );
+    pSRB = GetSRB( pACB );
+    if( !pSRB )
+    {
+	QLinkcmd( pcmd, pDCB );
+	restore_flags(flags);
+	return;
+    }
+
+    pSRB->pSRBDCB = pDCB;
+    pSRB->pcmd = pcmd;
+    ptr = (PUCHAR) pSRB->CmdBlock;
+    ptr1 = (PUCHAR) pcmd->cmnd;
+    pSRB->ScsiCmdLen = pcmd->cmd_len;
+    for(i=0; i< pcmd->cmd_len; i++)
+    {
+	*ptr = *ptr1;
+	ptr++;
+	ptr1++;
+    }
+    if( pcmd->use_sg )
+    {
+	pSRB->SGcount = (UCHAR) pcmd->use_sg;
+	pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+    }
+    else if( pcmd->request_buffer )
+    {
+	pSRB->SGcount = 1;
+	pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+	pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+	pSRB->Segmentx.length = pcmd->request_bufflen;
+    }
+    else
+	pSRB->SGcount = 0;
+
+    pSRB->SGIndex = 0;
+    pSRB->AdaptStatus = 0;
+    pSRB->TargetStatus = 0;
+    pSRB->MsgCnt = 0;
+    if( pDCB->DevType != TYPE_TAPE )
+	pSRB->RetryCnt = 1;
+    else
+	pSRB->RetryCnt = 0;
+    pSRB->SRBStatus = 0;
+    pSRB->SRBFlag = 0;
+    pSRB->SRBState = 0;
+    pSRB->TotalXferredLen = 0;
+    pSRB->SGPhysAddr = 0;
+    pSRB->SGToBeXferLen = 0;
+    pSRB->ScsiPhase = 0;
+    pSRB->EndMessage = 0;
+    SendSRB( pcmd, pACB, pSRB );
+
+    restore_flags(flags);
+    return;
+}
+
+
+/***********************************************************************
+ * Function:
+ *   DC390_bios_param
+ *
+ * Description:
+ *   Return the disk geometry for the given SCSI device.
+ ***********************************************************************/
+#ifdef	VERSION_ELF_1_2_13
+int DC390_bios_param(Disk *disk, int devno, int geom[])
+#else
+int DC390_bios_param(Disk *disk, kdev_t devno, int geom[])
+#endif
+{
+    int heads, sectors, cylinders;
+    PACB pACB;
+
+    pACB = (PACB) disk->device->host->hostdata;
+    heads = 64;
+    sectors = 32;
+    cylinders = disk->capacity / (heads * sectors);
+
+    if ( cylinders > 1024)
+    {
+      heads = 255;
+      sectors = 63;
+      cylinders = disk->capacity / (255 * 63);
+    }
+
+    geom[0] = heads;
+    geom[1] = sectors;
+    geom[2] = cylinders;
+
+    return (0);
+}
+
+
+/***********************************************************************
+ * Function : int DC390_abort (Scsi_Cmnd *cmd)
+ *
+ * Purpose : Abort an errant SCSI command
+ *
+ * Inputs : cmd - command to abort
+ *
+ * Returns : 0 on success, -1 on failure.
+ ***********************************************************************/
+
+int
+DC390_abort (Scsi_Cmnd *cmd)
+{
+    ULONG flags;
+    PACB  pACB;
+    PDCB  pDCB, pdcb;
+    PSRB  pSRB, psrb;
+    USHORT count, i;
+    PSCSICMD  pcmd, pcmd1;
+    int   status;
+
+
+#ifdef DC390_DEBUG0
+    printk("DC390 : Abort Cmd.");
+#endif
+
+    save_flags(flags);
+    cli();
+
+    pACB = (PACB) cmd->host->hostdata;
+    pDCB = pACB->pLinkDCB;
+    pdcb = pDCB;
+    while( (pDCB->UnitSCSIID != cmd->target) ||
+	   (pDCB->UnitSCSILUN != cmd->lun) )
+    {
+	pDCB = pDCB->pNextDCB;
+	if( pDCB == pdcb )
+	    goto  NOT_RUN;
+    }
+
+    if( pDCB->QIORBCnt )
+    {
+	pcmd = pDCB->pQIORBhead;
+	if( pcmd == cmd )
+	{
+	    pDCB->pQIORBhead = pcmd->next;
+	    pcmd->next = NULL;
+	    pDCB->QIORBCnt--;
+	    status = SCSI_ABORT_SUCCESS;
+	    goto  ABO_X;
+	}
+	for( count = pDCB->QIORBCnt, i=0; i<count-1; i++)
+	{
+	    if( pcmd->next == cmd )
+	    {
+		pcmd1 = pcmd->next;
+		pcmd->next = pcmd1->next;
+		pcmd1->next = NULL;
+		pDCB->QIORBCnt--;
+		status = SCSI_ABORT_SUCCESS;
+		goto  ABO_X;
+	    }
+	    else
+	    {
+		pcmd = pcmd->next;
+	    }
+	}
+    }
+
+    pSRB = pDCB->pWaitingSRB;
+    if( !pSRB )
+	goto  ON_GOING;
+    if( pSRB->pcmd == cmd )
+    {
+	pDCB->pWaitingSRB = pSRB->pNextSRB;
+	goto  IN_WAIT;
+    }
+    else
+    {
+	psrb = pSRB;
+	if( !(psrb->pNextSRB) )
+	    goto ON_GOING;
+	while( psrb->pNextSRB->pcmd != cmd )
+	{
+	    psrb = psrb->pNextSRB;
+	    if( !(psrb->pNextSRB) )
+		goto ON_GOING;
+	}
+	pSRB = psrb->pNextSRB;
+	psrb->pNextSRB = pSRB->pNextSRB;
+	if( pSRB == pDCB->pWaitLast )
+	    pDCB->pWaitLast = psrb; /* No check for psrb == NULL ? */
+IN_WAIT:
+	pSRB->pNextSRB = pACB->pFreeSRB;
+	pACB->pFreeSRB = pSRB;
+	cmd->next = NULL;
+	status = SCSI_ABORT_SUCCESS;
+	goto  ABO_X;
+    }
+
+ON_GOING:
+    pSRB = pDCB->pGoingSRB;
+    for( count = pDCB->GoingSRBCnt, i=0; i<count; i++)
+    {
+	if( pSRB->pcmd != cmd )
+	    pSRB = pSRB->pNextSRB;
+	else
+	{
+	    if( (pACB->pActiveDCB == pDCB) && (pDCB->pActiveSRB == pSRB) )
+	    {
+		status = SCSI_ABORT_BUSY;
+		goto  ABO_X;
+	    }
+	    else
+	    {
+		status = SCSI_ABORT_SNOOZE;
+		goto  ABO_X;
+	    }
+	}
+    }
+
+NOT_RUN:
+    status = SCSI_ABORT_NOT_RUNNING;
+
+ABO_X:
+    cmd->result = DID_ABORT << 16;
+    cmd->scsi_done(cmd);
+    restore_flags(flags);
+    return( status );
+}
+
+
+static void
+ResetDevParam( PACB pACB )
+{
+    PDCB   pDCB, pdcb;
+
+    pDCB = pACB->pLinkDCB;
+    if( pDCB == NULL )
+	return;
+    pdcb = pDCB;
+    do
+    {
+	pDCB->SyncMode &= ~SYNC_NEGO_DONE;
+	pDCB->SyncPeriod = 0;
+	pDCB->SyncOffset = 0;
+	pDCB->CtrlR3 = FAST_CLK;
+	pDCB->CtrlR4 &= NEGATE_REQACKDATA;
+	pDCB->CtrlR4 |= EATER_25NS;
+	pDCB = pDCB->pNextDCB;
+    }
+    while( pdcb != pDCB );
+}
+
+
+static void
+RecoverSRB( PACB pACB )
+{
+    PDCB   pDCB, pdcb;
+    PSRB   psrb, psrb2;
+    USHORT cnt, i;
+
+    pDCB = pACB->pLinkDCB;
+    if( pDCB == NULL )
+	return;
+    pdcb = pDCB;
+    do
+    {
+	cnt = pdcb->GoingSRBCnt;
+	psrb = pdcb->pGoingSRB;
+	for (i=0; i<cnt; i++)
+	{
+	    psrb2 = psrb;
+	    psrb = psrb->pNextSRB;
+/*	    RewaitSRB( pDCB, psrb ); */
+	    if( pdcb->pWaitingSRB )
+	    {
+		psrb2->pNextSRB = pdcb->pWaitingSRB;
+		pdcb->pWaitingSRB = psrb2;
+	    }
+	    else
+	    {
+		pdcb->pWaitingSRB = psrb2;
+		pdcb->pWaitLast = psrb2;
+		psrb2->pNextSRB = NULL;
+	    }
+	}
+	pdcb->GoingSRBCnt = 0;
+	pdcb->pGoingSRB = NULL;
+	pdcb->TagMask = 0;
+	pdcb = pdcb->pNextDCB;
+    }
+    while( pdcb != pDCB );
+}
+
+
+/***********************************************************************
+ * Function : int DC390_reset (Scsi_Cmnd *cmd, ...)
+ *
+ * Purpose : perform a hard reset on the SCSI bus
+ *
+ * Inputs : cmd - command which caused the SCSI RESET
+ *
+ * Returns : 0 on success.
+ ***********************************************************************/
+
+#ifdef	VERSION_2_0_0
+int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags)
+#else
+int DC390_reset (Scsi_Cmnd *cmd)
+#endif
+{
+    USHORT   ioport;
+    unsigned long flags;
+    PACB  pACB;
+    UCHAR    bval;
+    USHORT  i;
+
+
+#ifdef DC390_DEBUG1
+    printk("DC390: RESET,");
+#endif
+
+    pACB = (PACB ) cmd->host->hostdata;
+    ioport = pACB->IOPortBase;
+    save_flags(flags);
+    cli();
+    bval = inb(ioport+CtrlReg1);
+    bval |= DIS_INT_ON_SCSI_RST;
+    outb(bval,ioport+CtrlReg1);  /* disable interrupt */
+    DC390_ResetSCSIBus( pACB );
+    for( i=0; i<500; i++ )
+	udelay(1000);
+    bval = inb(ioport+CtrlReg1);
+    bval &= ~DIS_INT_ON_SCSI_RST;
+    outb(bval,ioport+CtrlReg1); /* re-enable interrupt */
+
+    bval = DMA_IDLE_CMD;
+    outb(bval,ioport+DMA_Cmd);
+    bval = CLEAR_FIFO_CMD;
+    outb(bval,ioport+ScsiCmd);
+
+    ResetDevParam( pACB );
+    DoingSRB_Done( pACB );
+    pACB->pActiveDCB = NULL;
+
+    pACB->ACBFlag = 0;
+    DoWaitingSRB( pACB );
+
+    restore_flags(flags);
+#ifdef DC390_DEBUG1
+    printk("DC390: RESET1,");
+#endif
+    return( SCSI_RESET_SUCCESS );
+}
+
+
+#include "scsiiom.c"
+
+
+/***********************************************************************
+ * Function : static void DC390_initDCB
+ *
+ * Purpose :  initialize the internal structures for a given DCB
+ *
+ * Inputs : cmd - pointer to this scsi cmd request block structure
+ *
+ ***********************************************************************/
+void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd )
+{
+    PEEprom	prom;
+    UCHAR	bval;
+    USHORT	index;
+
+    if( pACB->DeviceCnt == 0 )
+    {
+	pACB->pLinkDCB = pDCB;
+	pACB->pDCBRunRobin = pDCB;
+	pDCB->pNextDCB = pDCB;
+	pPrevDCB = pDCB;
+    }
+    else
+	pPrevDCB->pNextDCB = pDCB;
+
+    pDCB->pDCBACB = pACB;
+    pDCB->QIORBCnt = 0;
+    pDCB->UnitSCSIID = cmd->target;
+    pDCB->UnitSCSILUN = cmd->lun;
+    pDCB->pWaitingSRB = NULL;
+    pDCB->pGoingSRB = NULL;
+    pDCB->GoingSRBCnt = 0;
+    pDCB->pActiveSRB = NULL;
+    pDCB->TagMask = 0;
+    pDCB->MaxCommand = 1;
+    pDCB->AdaptIndex = pACB->AdapterIndex;
+    index = pACB->AdapterIndex;
+    pDCB->DCBFlag = 0;
+
+    prom = (PEEprom) &eepromBuf[index][cmd->target << 2];
+    pDCB->DevMode = prom->EE_MODE1;
+    pDCB->AdpMode = eepromBuf[index][EE_MODE2];
+
+    if( pDCB->DevMode & EN_DISCONNECT_ )
+	bval = 0xC0;
+    else
+	bval = 0x80;
+    bval |= cmd->lun;
+    pDCB->IdentifyMsg = bval;
+
+    pDCB->SyncMode = 0;
+    if( pDCB->DevMode & SYNC_NEGO_ )
+    {
+	if( !(cmd->lun) || CurrSyncOffset )
+	    pDCB->SyncMode = SYNC_ENABLE;
+    }
+
+    pDCB->SyncPeriod = 0;
+    pDCB->SyncOffset = 0;
+    pDCB->NegoPeriod = (clock_period1[prom->EE_SPEED] * 25) >> 2;
+
+    pDCB->CtrlR1 = pACB->AdaptSCSIID;
+    if( pDCB->DevMode & PARITY_CHK_ )
+	pDCB->CtrlR1 |= PARITY_ERR_REPO;
+
+    pDCB->CtrlR3 = FAST_CLK;
+
+    pDCB->CtrlR4 = EATER_25NS;
+    if( pDCB->AdpMode & ACTIVE_NEGATION)
+	pDCB->CtrlR4 |= NEGATE_REQACKDATA;
+}
+
+
+/***********************************************************************
+ * Function : static void DC390_initSRB
+ *
+ * Purpose :  initialize the internal structures for a given SRB
+ *
+ * Inputs : psrb - pointer to this scsi request block structure
+ *
+ ***********************************************************************/
+void DC390_initSRB( PSRB psrb )
+{
+#ifndef VERSION_ELF_1_2_13
+#ifdef DC390_DEBUG0
+   printk("DC390 init: %08lx %08lx,",(ULONG)psrb,(ULONG)virt_to_bus(psrb));
+#endif
+	psrb->PhysSRB = virt_to_bus( psrb );
+#else
+	psrb->PhysSRB = (ULONG) psrb;
+#endif
+}
+
+
+void DC390_linkSRB( PACB pACB )
+{
+    USHORT  count, i;
+    PSRB    psrb;
+
+    count = pACB->SRBCount;
+
+    for( i=0; i< count; i++)
+    {
+	if( i != count - 1)
+	    pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1];
+	else
+	    pACB->SRB_array[i].pNextSRB = NULL;
+	psrb = (PSRB) &pACB->SRB_array[i];
+	DC390_initSRB( psrb );
+    }
+}
+
+
+/***********************************************************************
+ * Function : static void DC390_initACB
+ *
+ * Purpose :  initialize the internal structures for a given SCSI host
+ *
+ * Inputs : psh - pointer to this host adapter's structure
+ *
+ ***********************************************************************/
+void DC390_initACB( PSH psh, ULONG io_port, UCHAR Irq, USHORT index )
+{
+    PACB    pACB;
+    USHORT  i;
+
+    psh->can_queue = MAX_CMD_QUEUE;
+    psh->cmd_per_lun = MAX_CMD_PER_LUN;
+    psh->this_id = (int) eepromBuf[index][EE_ADAPT_SCSI_ID];
+    psh->io_port = io_port;
+    psh->n_io_port = 0x80;
+    psh->irq = Irq;
+
+    pACB = (PACB) psh->hostdata;
+
+#ifndef VERSION_ELF_1_2_13
+    psh->max_id = 8;
+#ifdef	CONFIG_SCSI_MULTI_LUN
+    if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
+	psh->max_lun = 8;
+    else
+#endif
+	psh->max_lun = 1;
+#endif
+
+    pACB->max_id = 7;
+    if( pACB->max_id == eepromBuf[index][EE_ADAPT_SCSI_ID] )
+	pACB->max_id--;
+#ifdef	CONFIG_SCSI_MULTI_LUN
+    if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
+	pACB->max_lun = 7;
+    else
+#endif
+	pACB->max_lun = 0;
+
+    pACB->pScsiHost = psh;
+    pACB->IOPortBase = (USHORT) io_port;
+    pACB->pLinkDCB = NULL;
+    pACB->pDCBRunRobin = NULL;
+    pACB->pActiveDCB = NULL;
+    pACB->pFreeSRB = pACB->SRB_array;
+    pACB->SRBCount = MAX_SRB_CNT;
+    pACB->AdapterIndex = index;
+    pACB->status = 0;
+    pACB->AdaptSCSIID = eepromBuf[index][EE_ADAPT_SCSI_ID];
+    pACB->HostID_Bit = (1 << pACB->AdaptSCSIID);
+    pACB->AdaptSCSILUN = 0;
+    pACB->DeviceCnt = 0;
+    pACB->IRQLevel = Irq;
+    pACB->TagMaxNum = eepromBuf[index][EE_TAG_CMD_NUM] << 2;
+    pACB->ACBFlag = 0;
+    pACB->scan_devices = 1;
+    pACB->Gmode2 = eepromBuf[index][EE_MODE2];
+    if( eepromBuf[index][EE_MODE2] & LUN_CHECK )
+	pACB->LUNchk = 1;
+    pACB->pDCB_free = &pACB->DCB_array[0];
+    DC390_linkSRB( pACB );
+    pACB->pTmpSRB = &pACB->TmpSRB;
+    DC390_initSRB( pACB->pTmpSRB );
+    for(i=0; i<MAX_SCSI_ID; i++)
+	pACB->DCBmap[i] = 0;
+}
+
+
+/***********************************************************************
+ * Function : static int DC390_initAdapter
+ *
+ * Purpose :  initialize the SCSI chip ctrl registers
+ *
+ * Inputs : psh - pointer to this host adapter's structure
+ *
+ ***********************************************************************/
+int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index )
+{
+    USHORT ioport;
+    UCHAR  bval;
+    PACB   pACB, pacb;
+    USHORT used_irq = 0;
+
+    pacb = pACB_start;
+    if( pacb != NULL )
+    {
+	for ( ; (pacb != (PACB) -1) ; )
+	{
+	    if( pacb->IRQLevel == Irq )
+	    {
+		used_irq = 1;
+		break;
+	    }
+	    else
+		pacb = pacb->pNextACB;
+	}
+    }
+
+    if( !used_irq )
+    {
+#ifdef	VERSION_ELF_1_2_13
+	if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT, "tmscsim"))
+#else
+	if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT, "tmscsim", NULL))
+#endif
+	{
+	    printk("DC390: register IRQ error!\n");
+	    return( -1 );
+	}
+    }
+
+    request_region(io_port,psh->n_io_port,"tmscsim");
+
+    ioport = (USHORT) io_port;
+
+    pACB = (PACB) psh->hostdata;
+    bval = SEL_TIMEOUT; 		/* 250ms selection timeout */
+    outb(bval,ioport+Scsi_TimeOut);
+
+    bval = CLK_FREQ_40MHZ;		/* Conversion factor = 0 , 40MHz clock */
+    outb(bval,ioport+Clk_Factor);
+
+    bval = NOP_CMD;			/* NOP cmd - clear command register */
+    outb(bval,ioport+ScsiCmd);
+
+    bval = EN_FEATURE+EN_SCSI2_CMD;	/* Enable Feature and SCSI-2 */
+    outb(bval,ioport+CtrlReg2);
+
+    bval = FAST_CLK;			/* fast clock */
+    outb(bval,ioport+CtrlReg3);
+
+    bval = EATER_25NS;
+    if( eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION )
+	 bval |= NEGATE_REQACKDATA;
+    outb(bval,ioport+CtrlReg4);
+
+    bval = DIS_INT_ON_SCSI_RST; 	/* Disable SCSI bus reset interrupt */
+    outb(bval,ioport+CtrlReg1);
+
+    return(0);
+}
+
+
+void
+DC390_EnableCfg( USHORT mechnum, UCHAR regval )
+{
+    ULONG wlval;
+
+    if(mechnum == 2)
+    {
+	outb(mech2bus, PCI_CFG2_FORWARD_REG);
+	outb(mech2CfgSPenR, PCI_CFG2_ENABLE_REG);
+    }
+    else
+    {
+	regval &= 0xFC;
+	wlval = mech1addr;
+	wlval |= (((ULONG)regval) & 0xff);
+	outl(wlval, PCI_CFG1_ADDRESS_REG);
+    }
+}
+
+
+void
+DC390_DisableCfg( USHORT mechnum )
+{
+
+    if(mechnum == 2)
+	outb(0, PCI_CFG2_ENABLE_REG);
+    else
+	outl(0, PCI_CFG1_ADDRESS_REG);
+}
+
+
+UCHAR
+DC390_inByte( USHORT mechnum, UCHAR regval )
+{
+    UCHAR bval;
+    ULONG wval;
+    ULONG flags;
+
+    save_flags(flags);
+    cli();
+    DC390_EnableCfg( mechnum, regval );
+    if(mechnum == 2)
+    {
+	wval = mech2Agent;
+	wval <<= 8;
+	wval |= ((USHORT) regval) & 0xff;
+	bval = inb(wval);
+    }
+    else
+    {
+	regval &= 3;
+	bval = inb(PCI_CFG1_DATA_REG | regval);
+    }
+    DC390_DisableCfg(mechnum);
+    restore_flags(flags);
+    return(bval);
+}
+
+
+USHORT
+DC390_inWord( USHORT mechnum, UCHAR regval )
+{
+    USHORT wval;
+    ULONG flags;
+
+    save_flags(flags);
+    cli();
+    DC390_EnableCfg(mechnum,regval);
+    if(mechnum == 2)
+    {
+	wval = mech2Agent;
+	wval <<= 8;
+	wval |= regval;
+	wval = inw(wval);
+    }
+    else
+    {
+	regval &= 3;
+	wval = inw(PCI_CFG1_DATA_REG | regval);
+    }
+    DC390_DisableCfg(mechnum);
+    restore_flags(flags);
+    return(wval);
+}
+
+
+ULONG
+DC390_inDword(USHORT mechnum, UCHAR regval )
+{
+    ULONG wlval;
+    ULONG flags;
+    USHORT wval;
+
+    save_flags(flags);
+    cli();
+    DC390_EnableCfg(mechnum,regval);
+    if(mechnum == 2)
+    {
+	wval = mech2Agent;
+	wval <<= 8;
+	wval |= regval;
+	wlval = inl(wval);
+    }
+    else
+    {
+	wlval = inl(PCI_CFG1_DATA_REG);
+    }
+    DC390_DisableCfg(mechnum);
+    restore_flags(flags);
+    return(wlval);
+}
+
+
+void
+DC390_OutB(USHORT mechnum, UCHAR regval, UCHAR bval )
+{
+
+    USHORT wval;
+    ULONG  flags;
+
+    save_flags(flags);
+    cli();
+    DC390_EnableCfg(mechnum,regval);
+    if(mechnum == 2)
+    {
+	wval = mech2Agent;
+	wval <<= 8;
+	wval |= regval;
+	outb(bval, wval);
+    }
+    else
+    {
+	regval &= 3;
+	outb(bval, PCI_CFG1_DATA_REG | regval);
+    }
+    DC390_DisableCfg(mechnum);
+    restore_flags(flags);
+}
+
+
+void
+DC390_EnDisableCE( UCHAR mode, USHORT mechnum, PUCHAR regval )
+{
+
+    UCHAR bval;
+
+    bval = 0;
+    if(mode == ENABLE_CE)
+	*regval = 0xc0;
+    else
+	*regval = 0x80;
+    DC390_OutB(mechnum,*regval,bval);
+    if(mode == DISABLE_CE)
+	DC390_OutB(mechnum,*regval,bval);
+    udelay(160);
+}
+
+
+void
+DC390_EEpromOutDI( USHORT mechnum, PUCHAR regval, USHORT Carry )
+{
+    UCHAR bval;
+
+    bval = 0;
+    if(Carry)
+    {
+	bval = 0x40;
+	*regval = 0x80;
+	DC390_OutB(mechnum,*regval,bval);
+    }
+    udelay(160);
+    bval |= 0x80;
+    DC390_OutB(mechnum,*regval,bval);
+    udelay(160);
+    bval = 0;
+    DC390_OutB(mechnum,*regval,bval);
+    udelay(160);
+}
+
+
+UCHAR
+DC390_EEpromInDO( USHORT mechnum )
+{
+    UCHAR bval,regval;
+
+    regval = 0x80;
+    bval = 0x80;
+    DC390_OutB(mechnum,regval,bval);
+    udelay(160);
+    bval = 0x40;
+    DC390_OutB(mechnum,regval,bval);
+    udelay(160);
+    regval = 0x0;
+    bval = DC390_inByte(mechnum,regval);
+    if(bval == 0x22)
+	return(1);
+    else
+	return(0);
+}
+
+
+USHORT
+EEpromGetData1( USHORT mechnum )
+{
+    UCHAR i;
+    UCHAR carryFlag;
+    USHORT wval;
+
+    wval = 0;
+    for(i=0; i<16; i++)
+    {
+	wval <<= 1;
+	carryFlag = DC390_EEpromInDO(mechnum);
+	wval |= carryFlag;
+    }
+    return(wval);
+}
+
+
+void
+DC390_Prepare( USHORT mechnum, PUCHAR regval, UCHAR EEpromCmd )
+{
+    UCHAR i,j;
+    USHORT carryFlag;
+
+    carryFlag = 1;
+    j = 0x80;
+    for(i=0; i<9; i++)
+    {
+	DC390_EEpromOutDI(mechnum,regval,carryFlag);
+	carryFlag = (EEpromCmd & j) ? 1 : 0;
+	j >>= 1;
+    }
+}
+
+
+void
+DC390_ReadEEprom( USHORT mechnum, USHORT index )
+{
+    UCHAR   regval,cmd;
+    PUSHORT ptr;
+    USHORT  i;
+
+    ptr = (PUSHORT) &eepromBuf[index][0];
+    cmd = EEPROM_READ;
+    for(i=0; i<0x40; i++)
+    {
+	DC390_EnDisableCE(ENABLE_CE, mechnum, &regval);
+	DC390_Prepare(mechnum, &regval, cmd);
+	*ptr = EEpromGetData1(mechnum);
+	ptr++;
+	cmd++;
+	DC390_EnDisableCE(DISABLE_CE,mechnum,&regval);
+    }
+}
+
+
+USHORT
+DC390_CheckEEpromCheckSum( USHORT MechNum, USHORT index )
+{
+    USHORT wval, rc, *ptr;
+    UCHAR  i;
+
+    DC390_ReadEEprom( MechNum, index );
+    wval = 0;
+    ptr = (PUSHORT) &eepromBuf[index][0];
+    for(i=0; i<128 ;i+=2, ptr++)
+	wval += *ptr;
+    if( wval == 0x1234 )
+	rc = 0;
+    else
+	rc = -1;
+    return( rc );
+}
+
+
+USHORT
+DC390_ToMech( USHORT Mechnum, USHORT BusDevFunNum )
+{
+    USHORT devnum;
+
+    devnum = BusDevFunNum;
+
+    if(Mechnum == 2)
+    {
+	if(devnum & 0x80)
+	     return(-1);
+	mech2bus = (UCHAR)((devnum & 0xff00) >> 8);	  /* Bus num */
+	mech2Agent = ((UCHAR)(devnum & 0xff)) >> 3;	  /* Dev num */
+	mech2Agent |= 0xc0;
+	mech2CfgSPenR = ((UCHAR)(devnum & 0xff)) & 0x07;  /* Fun num */
+	mech2CfgSPenR = (mech2CfgSPenR << 1) | 0x20;
+    }
+    else	/* use mech #1 method */
+    {
+	mech1addr = 0x80000000 | ((ULONG)devnum << 8);
+    }
+    return(0);
+}
+
+/***********************************************************************
+ * Function : static int DC390_init (struct Scsi_Host *host)
+ *
+ * Purpose :  initialize the internal structures for a given SCSI host
+ *
+ * Inputs : host - pointer to this host adapter's structure/
+ *
+ * Preconditions : when this function is called, the chip_type
+ *	field of the pACB structure MUST have been set.
+ ***********************************************************************/
+
+static int
+DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, USHORT index, USHORT MechNum)
+{
+    PSH   psh;
+    PACB  pACB;
+
+    if( !DC390_CheckEEpromCheckSum( MechNum, index) )
+    {
+	psh = scsi_register( psht, sizeof(DC390_ACB) );
+	if( !psh )
+	    return( -1 );
+	if( !pSH_start )
+	{
+	    pSH_start = psh;
+	    pSH_current = psh;
+	}
+	else
+	{
+	    pSH_current->next = psh;
+	    pSH_current = psh;
+	}
+
+#ifdef DC390_DEBUG0
+	printk("DC390: pSH = %8x,", (UINT) psh);
+	printk("DC390: Index %02i,", index);
+#endif
+
+	DC390_initACB( psh, io_port, Irq, index );
+	if( !DC390_initAdapter( psh, io_port, Irq, index ) )
+	{
+	    pACB = (PACB) psh->hostdata;
+	    if( !pACB_start )
+	    {
+		pACB_start = pACB;
+		pACB_current = pACB;
+		pACB->pNextACB = (PACB) -1;
+	    }
+	    else
+	    {
+		pACB_current->pNextACB = pACB;
+		pACB_current = pACB;
+		pACB->pNextACB = (PACB)  -1;
+	    }
+
+#ifdef DC390_DEBUG0
+	printk("DC390: pACB = %8x, pDCB_array = %8x, pSRB_array = %8x\n",
+	      (UINT) pACB, (UINT) pACB->DCB_array, (UINT) pACB->SRB_array);
+	printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",
+	      sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) );
+#endif
+
+	}
+	else
+	{
+	    pSH_start = NULL;
+	    scsi_unregister( psh );
+	    return( -1 );
+	}
+	return( 0 );
+    }
+    else
+    {
+	printk("DC390_init: EEPROM reading error!\n");
+	return( -1 );
+    }
+}
+
+
+/***********************************************************************
+ * Function : int DC390_detect(Scsi_Host_Template *psht)
+ *
+ * Purpose : detects and initializes AMD53C974 SCSI chips
+ *	     that were autoprobed, overridden on the LILO command line,
+ *	     or specified at compile time.
+ *
+ * Inputs : psht - template for this SCSI adapter
+ *
+ * Returns : number of host adapters detected
+ *
+ ***********************************************************************/
+
+int
+DC390_detect(Scsi_Host_Template *psht)
+{
+#ifdef FOR_PCI_OK
+    UCHAR   pci_bus, pci_device_fn;
+    int     error = 0;
+    USHORT  chipType = 0;
+    USHORT  i;
+#endif
+
+    UCHAR   irq;
+    UCHAR   istatus;
+#ifndef VERSION_ELF_1_2_13
+    UINT    io_port;
+#else
+    ULONG   io_port;
+#endif
+    USHORT  adaptCnt = 0;	/* Number of boards detected */
+    USHORT  pci_index = 0;	/* Device index to PCI BIOS calls */
+    USHORT  MechNum, BusDevFunNum;
+    ULONG   wlval;
+
+#ifndef VERSION_ELF_1_2_13
+    psht->proc_dir = &proc_scsi_tmscsim;
+#endif
+
+    InitialTime = 1;
+    pSHT_start = psht;
+    pACB_start = NULL;
+
+    MechNum = 1;
+    for( ; (MechNum < 3) && (!adaptCnt); MechNum++)
+    {
+	BusDevFunNum = 0;
+	for (; adaptCnt < MAX_ADAPTER_NUM ;)
+	{
+	    if( !DC390_ToMech( MechNum, BusDevFunNum) )
+	    {
+		 wlval = DC390_inDword( MechNum, PCI_VENDOR_ID);
+		 if(wlval == ( (PCI_DEVICE_ID_AMD53C974 << 16)+
+				PCI_VENDOR_ID_AMD) )
+		 {
+		    io_port =DC390_inDword(MechNum,PCI_BASE_ADDRESS_0) & 0xFFFE;
+		    irq = DC390_inByte( MechNum, PCI_INTERRUPT_LINE);
+#ifdef DC390_DEBUG0
+		printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq);
+#endif
+		    if( !DC390_init(psht, io_port, irq, pci_index, MechNum) )
+		    {
+			adaptCnt++;
+			pci_index++;
+			istatus = inb( (USHORT)io_port+INT_Status );	/* Reset Pending INT */
+#ifdef DC390_DEBUG0
+		printk("DC390: Mech=%2x,\n",(UCHAR) MechNum);
+#endif
+		    }
+		 }
+	    }
+	    if( BusDevFunNum != 0xfff8 )
+		BusDevFunNum += 8;	    /* next device # */
+	    else
+		break;
+	}
+    }
+
+#ifdef FOR_PCI_OK
+    if ( pcibios_present() )
+    {
+	for (i = 0; i < MAX_ADAPTER_NUM; ++i)
+	{
+	    if( !pcibios_find_device( PCI_VENDOR_ID_AMD,
+				PCI_DEVICE_ID_AMD53C974,
+				pci_index, &pci_bus, &pci_device_fn) )
+	    {
+		chipType = PCI_DEVICE_ID_AMD53C974;
+		pci_index++;
+	    }
+
+	    if( chipType )
+	    {
+
+		error = pcibios_read_config_dword(pci_bus, pci_device_fn,
+						  PCI_BASE_ADDRESS_0, &io_port);
+		error |= pcibios_read_config_byte(pci_bus, pci_device_fn,
+						  PCI_INTERRUPT_LINE, &irq);
+		if( error )
+		{
+		    printk("DC390_detect: reading configuration registers error!\n");
+		    InitialTime = 0;
+		    return( 0 );
+		}
+
+		(USHORT) io_port = (USHORT) io_port & 0xFFFE;
+#ifdef DC390_DEBUG0
+		printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq);
+#endif
+		if( !DC390_init(psht, io_port, irq, i) )
+		    adaptCnt++;
+		chipType = 0;
+	    }
+	    else
+		break;
+	}
+    }
+#endif
+
+    InitialTime = 0;
+    adapterCnt = adaptCnt;
+    return( adaptCnt );
+}
+
+
+#ifndef VERSION_ELF_1_2_13
+
+/********************************************************************
+ * Function: tmscsim_set_info()
+ *
+ * Purpose: Set adapter info (!)
+ *
+ * Not yet implemented
+ *
+ *******************************************************************/
+
+int tmscsim_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
+{
+  return(-ENOSYS);  /* Currently this is a no-op */
+}
+
+/********************************************************************
+ * Function: tmscsim_proc_info(char* buffer, char **start,
+ *			     off_t offset, int length, int hostno, int inout)
+ *
+ * Purpose: return SCSI Adapter/Device Info
+ *
+ * Input: buffer: Pointer to a buffer where to write info
+ *	  start :
+ *	  offset:
+ *	  hostno: Host adapter index
+ *	  inout : Read (=0) or set(!=0) info
+ *
+ * Output: buffer: contains info
+ *	   length; length of info in buffer
+ *
+ * return value: length
+ *
+ ********************************************************************/
+
+/* KG: proc_info taken from driver aha152x.c */
+
+#undef SPRINTF
+#define SPRINTF(args...) pos += sprintf(pos, ## args)
+
+#define YESNO(YN)\
+if (YN) SPRINTF(" Yes ");\
+else SPRINTF(" No  ")
+
+int tmscsim_proc_info(char *buffer, char **start,
+		      off_t offset, int length, int hostno, int inout)
+{
+  int dev, spd, spd1;
+  char *pos = buffer;
+  PSH shpnt;
+  PACB acbpnt;
+  PDCB dcbpnt;
+  unsigned long flags;
+/*  Scsi_Cmnd *ptr; */
+
+  acbpnt = pACB_start;
+
+  while(acbpnt != (PACB)-1)
+     {
+	shpnt = acbpnt->pScsiHost;
+	if (shpnt->host_no == hostno) break;
+	acbpnt = acbpnt->pNextACB;
+     }
+
+  if (acbpnt == (PACB)-1) return(-ESRCH);
+  if(!shpnt) return(-ESRCH);
+
+  if(inout) // Has data been written to the file ?
+    return(tmscsim_set_info(buffer, length, shpnt));
+
+  SPRINTF("Tekram DC390(T) PCI SCSI Host Adadpter, ");
+  SPRINTF("Driver Version 1.10, 1996/12/05\n");
+
+  save_flags(flags);
+  cli();
+
+  SPRINTF("SCSI Host Nr %i, ", shpnt->host_no);
+  SPRINTF("DC390 Adapter Nr %i\n", acbpnt->AdapterIndex);
+  SPRINTF("IOPortBase 0x%04x, ", acbpnt->IOPortBase);
+  SPRINTF("IRQLevel 0x%02x\n", acbpnt->IRQLevel);
+
+  SPRINTF("MaxID %i, MaxLUN %i, ",acbpnt->max_id, acbpnt->max_lun);
+  SPRINTF("AdapterID %i, AdapterLUN %i\n", acbpnt->AdaptSCSIID, acbpnt->AdaptSCSILUN);
+
+  SPRINTF("TagMaxNum %i, Status %i\n", acbpnt->TagMaxNum, acbpnt->status);
+
+  SPRINTF("Nr of attached devices: %i\n", acbpnt->DeviceCnt);
+
+  SPRINTF("Un ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs\n");
+
+  dcbpnt = acbpnt->pLinkDCB;
+  for (dev = 0; dev < acbpnt->DeviceCnt; dev++)
+     {
+      SPRINTF("%02i %02i  %02i ", dev, dcbpnt->UnitSCSIID, dcbpnt->UnitSCSILUN);
+      YESNO(dcbpnt->DevMode & PARITY_CHK_);
+      YESNO(dcbpnt->SyncMode & SYNC_NEGO_DONE);
+      YESNO(dcbpnt->DevMode & EN_DISCONNECT_);
+      YESNO(dcbpnt->DevMode & SEND_START_);
+      YESNO(dcbpnt->SyncMode & EN_TAG_QUEUING);
+      SPRINTF("  %03i ns ", (dcbpnt->NegoPeriod) << 2);
+      if (dcbpnt->SyncOffset & 0x0f)
+      {
+	 spd = 1000/(dcbpnt->NegoPeriod <<2);
+	 spd1 = 1000%(dcbpnt->NegoPeriod <<2);
+	 spd1 = (spd1 * 10)/(dcbpnt->NegoPeriod <<2);
+	 SPRINTF("   %2i.%1i M      %02i\n", spd, spd1, (dcbpnt->SyncOffset & 0x0f));
+      }
+      else SPRINTF("\n");
+      /* Add more info ...*/
+      dcbpnt = dcbpnt->pNextDCB;
+     }
+
+  restore_flags(flags);
+  *start = buffer + offset;
+
+  if (pos - buffer < offset)
+    return 0;
+  else if (pos - buffer - offset < length)
+    return pos - buffer - offset;
+  else
+    return length;
+}
+#endif /* VERSION_ELF_1_2_13 */
+
+
+#ifdef MODULE
+
+/***********************************************************************
+ * Function : static int DC390_shutdown (struct Scsi_Host *host)
+ *
+ * Purpose : does a clean (we hope) shutdown of the SCSI chip.
+ *	     Use prior to dumping core, unloading the driver, etc.
+ *
+ * Returns : 0 on success
+ ***********************************************************************/
+static int
+DC390_shutdown (struct Scsi_Host *host)
+{
+    UCHAR    bval;
+    USHORT   ioport;
+    unsigned long flags;
+    PACB pACB = (PACB)(host->hostdata);
+
+    ioport = (unsigned int) pACB->IOPortBase;
+
+    save_flags (flags);
+    cli();
+
+/*  pACB->soft_reset(host); */
+
+#ifdef DC390_DEBUG0
+    printk("DC390: shutdown,");
+#endif
+
+    bval = inb(ioport+CtrlReg1);
+    bval |= DIS_INT_ON_SCSI_RST;
+    outb(bval,ioport+CtrlReg1);  /* disable interrupt */
+    DC390_ResetSCSIBus( pACB );
+
+    restore_flags (flags);
+    return( 0 );
+}
+
+
+int DC390_release(struct Scsi_Host *host)
+{
+    int irq_count;
+    struct Scsi_Host *tmp;
+
+    DC390_shutdown (host);
+
+    if (host->irq != IRQ_NONE)
+    {
+	for (irq_count = 0, tmp = pSH_start; tmp; tmp = tmp->next)
+	{
+	    if ( tmp->irq == host->irq )
+		++irq_count;
+	}
+	if (irq_count == 1)
+	 {
+#ifdef DC390_DEBUG0
+	    printk("DC390: Free IRQ %i.",host->irq);
+#endif
+#ifndef VERSION_ELF_1_2_13
+	    free_irq(host->irq,NULL);
+#else
+	    free_irq(host->irq);
+#endif
+	 }
+    }
+
+    release_region(host->io_port,host->n_io_port);
+
+    return( 1 );
+}
+
+Scsi_Host_Template driver_template = DC390_T;
+#include "scsi_module.c"
+#endif /* def MODULE */
+
diff -urN linux-2.0.31-pre5/drivers/scsi/tmscsim.h linux-2.0.31-pre6/drivers/scsi/tmscsim.h
--- linux-2.0.31-pre5/drivers/scsi/tmscsim.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.31-pre6/drivers/scsi/tmscsim.h	2003-08-15 15:04:01.000000000 -0700
@@ -0,0 +1,680 @@
+/***********************************************************************
+;*	File Name : TMSCSIM.H					       *
+;*		    TEKRAM DC-390(T) PCI SCSI Bus Master Host Adapter  *
+;*		    Device Driver				       *
+;***********************************************************************/
+
+#ifndef TMSCSIM_H
+#define TMSCSIM_H
+
+#define IRQ_NONE 255
+
+typedef unsigned char	UCHAR;
+typedef unsigned short	USHORT;
+typedef unsigned long	ULONG;
+typedef unsigned int	UINT;
+
+typedef UCHAR		*PUCHAR;
+typedef USHORT		*PUSHORT;
+typedef ULONG		*PULONG;
+typedef Scsi_Host_Template  *PSHT;
+typedef struct Scsi_Host    *PSH;
+typedef Scsi_Device	*PSCSIDEV;
+typedef Scsi_Cmnd	*PSCSICMD;
+typedef void		*PVOID;
+typedef struct scatterlist  *PSGL, SGL;
+
+
+/*;-----------------------------------------------------------------------*/
+typedef  struct  _SyncMsg
+{
+UCHAR		ExtendMsg;
+UCHAR		ExtMsgLen;
+UCHAR		SyncXferReq;
+UCHAR		Period;
+UCHAR		ReqOffset;
+} SyncMsg;
+/*;-----------------------------------------------------------------------*/
+typedef  struct  _Capacity
+{
+ULONG		BlockCount;
+ULONG		BlockLength;
+} Capacity;
+/*;-----------------------------------------------------------------------*/
+typedef  struct  _SGentry
+{
+ULONG		SGXferDataPtr;
+ULONG		SGXferDataLen;
+} SGentry;
+
+typedef  struct  _SGentry1
+{
+ULONG		SGXLen;
+ULONG		SGXPtr;
+} SGentry1, *PSGE;
+
+
+#define MAX_ADAPTER_NUM 	4
+#define MAX_DEVICES		10
+#define MAX_SG_LIST_BUF 	16
+#define MAX_CMD_QUEUE		20
+#define MAX_CMD_PER_LUN 	8
+#define MAX_SCSI_ID		8
+#define MAX_SRB_CNT		MAX_CMD_QUEUE+4
+#define END_SCAN		2
+
+#define SEL_TIMEOUT		153	/* 250 ms selection timeout (@ 40 MHz) */
+
+/*
+;-----------------------------------------------------------------------
+; SCSI Request Block
+;-----------------------------------------------------------------------
+*/
+struct	_SRB
+{
+UCHAR		CmdBlock[12];
+
+struct _SRB	*pNextSRB;
+struct _DCB	*pSRBDCB;
+PSCSICMD	pcmd;
+PSGL		pSegmentList;
+
+ULONG		PhysSRB;
+ULONG		TotalXferredLen;
+ULONG		SGPhysAddr;	/*;a segment starting address */
+ULONG		SGToBeXferLen;	/*; to be xfer length */
+
+SGL		Segmentx;	/* make a one entry of S/G list table */
+
+PUCHAR		pMsgPtr;
+USHORT		SRBState;
+USHORT		Revxx2; 	/* ??? */
+
+UCHAR		MsgInBuf[6];
+UCHAR		MsgOutBuf[6];
+
+UCHAR		AdaptStatus;
+UCHAR		TargetStatus;
+UCHAR		MsgCnt;
+UCHAR		EndMessage;
+UCHAR		TagNumber;
+UCHAR		SGcount;
+UCHAR		SGIndex;
+UCHAR		IORBFlag;	/*;81h-Reset, 2-retry */
+
+UCHAR		SRBStatus;
+UCHAR		RetryCnt;
+UCHAR		SRBFlag;	/*; b0-AutoReqSense,b6-Read,b7-write */
+				/*; b4-settimeout,b5-Residual valid */
+UCHAR		ScsiCmdLen;
+UCHAR		ScsiPhase;
+UCHAR		Reserved3[3];	/*;for dword alignment */
+ULONG		Segment0[2];
+ULONG		Segment1[2];
+};
+
+typedef  struct  _SRB	 DC390_SRB, *PSRB;
+
+/*
+;-----------------------------------------------------------------------
+; Device Control Block
+;-----------------------------------------------------------------------
+*/
+struct	_DCB
+{
+struct _DCB	*pNextDCB;
+struct _ACB	*pDCBACB;
+
+PSCSICMD	pQIORBhead;
+PSCSICMD	pQIORBtail;
+PSCSICMD	AboIORBhead;
+PSCSICMD	AboIORBtail;
+USHORT		QIORBCnt;
+USHORT		AboIORBcnt;
+
+PSRB		pWaitingSRB;
+PSRB		pWaitLast;
+PSRB		pGoingSRB;
+PSRB		pGoingLast;
+PSRB		pActiveSRB;
+USHORT		GoingSRBCnt;
+USHORT		WaitSRBCnt;	/* ??? */
+
+ULONG		TagMask;
+
+USHORT		MaxCommand;
+USHORT		AdaptIndex;	/*; UnitInfo struc start */
+USHORT		UnitIndex;	/*; nth Unit on this card */
+UCHAR		UnitSCSIID;	/*; SCSI Target ID  (SCSI Only) */
+UCHAR		UnitSCSILUN;	/*; SCSI Log.  Unit (SCSI Only) */
+
+UCHAR		IdentifyMsg;
+UCHAR		CtrlR1;
+UCHAR		CtrlR3;
+UCHAR		CtrlR4;
+
+UCHAR		InqDataBuf[8];
+UCHAR		CapacityBuf[8];
+UCHAR		DevMode;
+UCHAR		AdpMode;
+UCHAR		SyncMode;	/*; 0:async mode */
+UCHAR		NegoPeriod;	/*;for nego. */
+UCHAR		SyncPeriod;	/*;for reg. */
+UCHAR		SyncOffset;	/*;for reg. and nego.(low nibble) */
+UCHAR		UnitCtrlFlag;
+UCHAR		DCBFlag;
+UCHAR		DevType;
+UCHAR		Reserved2[3];	/*;for dword alignment */
+};
+
+typedef  struct  _DCB	 DC390_DCB, *PDCB;
+/*
+;-----------------------------------------------------------------------
+; Adapter Control Block
+;-----------------------------------------------------------------------
+*/
+struct	_ACB
+{
+ULONG		PhysACB;
+PSH		pScsiHost;
+struct _ACB	*pNextACB;
+USHORT		IOPortBase;
+USHORT		Revxx1; 	/* ??? */
+
+PDCB		pLinkDCB;
+PDCB		pDCBRunRobin;
+PDCB		pActiveDCB;
+PDCB		pDCB_free;
+PSRB		pFreeSRB;
+PSRB		pTmpSRB;
+USHORT		SRBCount;
+USHORT		AdapterIndex;	/*; nth Adapter this driver */
+USHORT		max_id;
+USHORT		max_lun;
+
+UCHAR		msgin123[4];
+UCHAR		status;
+UCHAR		AdaptSCSIID;	/*; Adapter SCSI Target ID */
+UCHAR		AdaptSCSILUN;	/*; Adapter SCSI LUN */
+UCHAR		DeviceCnt;
+UCHAR		IRQLevel;
+UCHAR		TagMaxNum;
+UCHAR		ACBFlag;
+UCHAR		Gmode2;
+UCHAR		LUNchk;
+UCHAR		scan_devices;
+UCHAR		HostID_Bit;
+UCHAR		Reserved1[1];	/*;for dword alignment */
+UCHAR		DCBmap[MAX_SCSI_ID];
+DC390_DCB	DCB_array[MAX_DEVICES]; 	/* +74h,  Len=3E8 */
+DC390_SRB	SRB_array[MAX_SRB_CNT]; 	/* +45Ch, Len=	*/
+DC390_SRB	TmpSRB;
+};
+
+typedef  struct  _ACB	 DC390_ACB, *PACB;
+
+/*;-----------------------------------------------------------------------*/
+
+
+#define BIT31	0x80000000
+#define BIT30	0x40000000
+#define BIT29	0x20000000
+#define BIT28	0x10000000
+#define BIT27	0x08000000
+#define BIT26	0x04000000
+#define BIT25	0x02000000
+#define BIT24	0x01000000
+#define BIT23	0x00800000
+#define BIT22	0x00400000
+#define BIT21	0x00200000
+#define BIT20	0x00100000
+#define BIT19	0x00080000
+#define BIT18	0x00040000
+#define BIT17	0x00020000
+#define BIT16	0x00010000
+#define BIT15	0x00008000
+#define BIT14	0x00004000
+#define BIT13	0x00002000
+#define BIT12	0x00001000
+#define BIT11	0x00000800
+#define BIT10	0x00000400
+#define BIT9	0x00000200
+#define BIT8	0x00000100
+#define BIT7	0x00000080
+#define BIT6	0x00000040
+#define BIT5	0x00000020
+#define BIT4	0x00000010
+#define BIT3	0x00000008
+#define BIT2	0x00000004
+#define BIT1	0x00000002
+#define BIT0	0x00000001
+
+/*;---UnitCtrlFlag */
+#define UNIT_ALLOCATED	BIT0
+#define UNIT_INFO_CHANGED BIT1
+#define FORMATING_MEDIA BIT2
+#define UNIT_RETRY	BIT3
+
+/*;---UnitFlags */
+#define DASD_SUPPORT	BIT0
+#define SCSI_SUPPORT	BIT1
+#define ASPI_SUPPORT	BIT2
+
+/*;----SRBState machine definition */
+#define SRB_FREE	0
+#define SRB_WAIT	BIT0
+#define SRB_READY	BIT1
+#define SRB_MSGOUT	BIT2	/*;arbitration+msg_out 1st byte*/
+#define SRB_MSGIN	BIT3
+#define SRB_MSGIN_MULTI BIT4
+#define SRB_COMMAND	BIT5
+#define SRB_START_	BIT6	/*;arbitration+msg_out+command_out*/
+#define SRB_DISCONNECT	BIT7
+#define SRB_DATA_XFER	BIT8
+#define SRB_XFERPAD	BIT9
+#define SRB_STATUS	BIT10
+#define SRB_COMPLETED	BIT11
+#define SRB_ABORT_SENT	BIT12
+#define DO_SYNC_NEGO	BIT13
+#define SRB_UNEXPECT_RESEL BIT14
+
+/*;---ACBFlag */
+#define RESET_DEV	BIT0
+#define RESET_DETECT	BIT1
+#define RESET_DONE	BIT2
+
+/*;---DCBFlag */
+#define ABORT_DEV_	BIT0
+
+/*;---SRBstatus */
+#define SRB_OK		BIT0
+#define ABORTION	BIT1
+#define OVER_RUN	BIT2
+#define UNDER_RUN	BIT3
+#define PARITY_ERROR	BIT4
+#define SRB_ERROR	BIT5
+
+/*;---SRBFlag */
+#define DATAOUT 	BIT7
+#define DATAIN		BIT6
+#define RESIDUAL_VALID	BIT5
+#define ENABLE_TIMER	BIT4
+#define RESET_DEV0	BIT2
+#define ABORT_DEV	BIT1
+#define AUTO_REQSENSE	BIT0
+
+/*;---Adapter status */
+#define H_STATUS_GOOD	 0
+#define H_SEL_TIMEOUT	 0x11
+#define H_OVER_UNDER_RUN 0x12
+#define H_UNEXP_BUS_FREE 0x13
+#define H_TARGET_PHASE_F 0x14
+#define H_INVALID_CCB_OP 0x16
+#define H_LINK_CCB_BAD	 0x17
+#define H_BAD_TARGET_DIR 0x18
+#define H_DUPLICATE_CCB  0x19
+#define H_BAD_CCB_OR_SG  0x1A
+#define H_ABORT 	 0x0FF
+
+/*; SCSI Status byte codes*/
+#define SCSI_STAT_GOOD		0x0	/*;  Good status */
+#define SCSI_STAT_CHECKCOND	0x02	/*;  SCSI Check Condition */
+#define SCSI_STAT_CONDMET	0x04	/*;  Condition Met */
+#define SCSI_STAT_BUSY		0x08	/*;  Target busy status */
+#define SCSI_STAT_INTER 	0x10	/*;  Intermediate status */
+#define SCSI_STAT_INTERCONDMET	0x14	/*;  Intermediate condition met */
+#define SCSI_STAT_RESCONFLICT	0x18	/*;  Reservation conflict */
+#define SCSI_STAT_CMDTERM	0x22	/*;  Command Terminated */
+#define SCSI_STAT_QUEUEFULL	0x28	/*;  Queue Full */
+
+#define SCSI_STAT_UNEXP_BUS_F	0xFD	/*;  Unexpect Bus Free */
+#define SCSI_STAT_BUS_RST_DETECT 0xFE	/*;  Scsi Bus Reset detected */
+#define SCSI_STAT_SEL_TIMEOUT	0xFF	/*;  Selection Time out */
+
+/*;---Sync_Mode */
+#define SYNC_DISABLE	0
+#define SYNC_ENABLE	BIT0
+#define SYNC_NEGO_DONE	BIT1
+#define WIDE_ENABLE	BIT2
+#define WIDE_NEGO_DONE	BIT3
+#define EN_TAG_QUEUING	BIT4
+#define EN_ATN_STOP	BIT5
+
+#define SYNC_NEGO_OFFSET 15
+
+/*;---SCSI bus phase*/
+#define SCSI_DATA_OUT	0
+#define SCSI_DATA_IN	1
+#define SCSI_COMMAND	2
+#define SCSI_STATUS_	3
+#define SCSI_NOP0	4
+#define SCSI_NOP1	5
+#define SCSI_MSG_OUT	6
+#define SCSI_MSG_IN	7
+
+/*;----SCSI MSG BYTE*/
+#define MSG_COMPLETE		0x00
+#define MSG_EXTENDED		0x01
+#define MSG_SAVE_PTR		0x02
+#define MSG_RESTORE_PTR 	0x03
+#define MSG_DISCONNECT		0x04
+#define MSG_INITIATOR_ERROR	0x05
+#define MSG_ABORT		0x06
+#define MSG_REJECT_		0x07
+#define MSG_NOP 		0x08
+#define MSG_PARITY_ERROR	0x09
+#define MSG_LINK_CMD_COMPL	0x0A
+#define MSG_LINK_CMD_COMPL_FLG	0x0B
+#define MSG_BUS_RESET		0x0C
+#define MSG_ABORT_TAG		0x0D
+#define MSG_SIMPLE_QTAG 	0x20
+#define MSG_HEAD_QTAG		0x21
+#define MSG_ORDER_QTAG		0x22
+#define MSG_IDENTIFY		0x80
+#define MSG_HOST_ID		0x0C0
+
+/*;----SCSI STATUS BYTE*/
+#define STATUS_GOOD		0x00
+#define CHECK_CONDITION_	0x02
+#define STATUS_BUSY		0x08
+#define STATUS_INTERMEDIATE	0x10
+#define RESERVE_CONFLICT	0x18
+
+/* cmd->result */
+#define STATUS_MASK_		0xFF
+#define MSG_MASK		0xFF00
+#define RETURN_MASK		0xFF0000
+
+/*
+**  Inquiry Data format
+*/
+
+typedef struct	_SCSIInqData { /* INQ */
+
+	UCHAR	 DevType;		/* Periph Qualifier & Periph Dev Type*/
+	UCHAR	 RMB_TypeMod;		/* rem media bit & Dev Type Modifier */
+	UCHAR	 Vers;			/* ISO, ECMA, & ANSI versions	     */
+	UCHAR	 RDF;			/* AEN, TRMIOP, & response data format*/
+	UCHAR	 AddLen;		/* length of additional data	     */
+	UCHAR	 Res1;			/* reserved			     */
+	UCHAR	 Res2;			/* reserved			     */
+	UCHAR	 Flags; 		/* RelADr,Wbus32,Wbus16,Sync,etc.    */
+	UCHAR	 VendorID[8];		/* Vendor Identification	     */
+	UCHAR	 ProductID[16]; 	/* Product Identification	     */
+	UCHAR	 ProductRev[4]; 	/* Product Revision		     */
+
+
+} SCSI_INQDATA, *PSCSI_INQDATA;
+
+
+/*  Inquiry byte 0 masks */
+
+
+#define SCSI_DEVTYPE	    0x1F      /* Peripheral Device Type 	    */
+#define SCSI_PERIPHQUAL     0xE0      /* Peripheral Qualifier		    */
+
+
+/*  Inquiry byte 1 mask */
+
+#define SCSI_REMOVABLE_MEDIA  0x80    /* Removable Media bit (1=removable)  */
+
+
+/*  Peripheral Device Type definitions */
+
+#define SCSI_DASD		 0x00	   /* Direct-access Device	   */
+#define SCSI_SEQACESS		 0x01	   /* Sequential-access device	   */
+#define SCSI_PRINTER		 0x02	   /* Printer device		   */
+#define SCSI_PROCESSOR		 0x03	   /* Processor device		   */
+#define SCSI_WRITEONCE		 0x04	   /* Write-once device 	   */
+#define SCSI_CDROM		 0x05	   /* CD-ROM device		   */
+#define SCSI_SCANNER		 0x06	   /* Scanner device		   */
+#define SCSI_OPTICAL		 0x07	   /* Optical memory device	   */
+#define SCSI_MEDCHGR		 0x08	   /* Medium changer device	   */
+#define SCSI_COMM		 0x09	   /* Communications device	   */
+#define SCSI_NODEV		 0x1F	   /* Unknown or no device type    */
+
+/*
+** Inquiry flag definitions (Inq data byte 7)
+*/
+
+#define SCSI_INQ_RELADR       0x80    /* device supports relative addressing*/
+#define SCSI_INQ_WBUS32       0x40    /* device supports 32 bit data xfers  */
+#define SCSI_INQ_WBUS16       0x20    /* device supports 16 bit data xfers  */
+#define SCSI_INQ_SYNC	      0x10    /* device supports synchronous xfer   */
+#define SCSI_INQ_LINKED       0x08    /* device supports linked commands    */
+#define SCSI_INQ_CMDQUEUE     0x02    /* device supports command queueing   */
+#define SCSI_INQ_SFTRE	      0x01    /* device supports soft resets */
+
+
+/*
+;==========================================================
+; EEPROM byte offset
+;==========================================================
+*/
+typedef  struct  _EEprom
+{
+UCHAR	EE_MODE1;
+UCHAR	EE_SPEED;
+UCHAR	xx1;
+UCHAR	xx2;
+} EEprom, *PEEprom;
+
+#define EE_ADAPT_SCSI_ID 64
+#define EE_MODE2	65
+#define EE_DELAY	66
+#define EE_TAG_CMD_NUM	67
+
+/*; EE_MODE1 bits definition*/
+#define PARITY_CHK_	BIT0
+#define SYNC_NEGO_	BIT1
+#define EN_DISCONNECT_	BIT2
+#define SEND_START_	BIT3
+#define TAG_QUEUING_	BIT4
+
+/*; EE_MODE2 bits definition*/
+#define MORE2_DRV	BIT0
+#define GREATER_1G	BIT1
+#define RST_SCSI_BUS	BIT2
+#define ACTIVE_NEGATION BIT3
+#define NO_SEEK 	BIT4
+#define LUN_CHECK	BIT5
+
+#define ENABLE_CE	1
+#define DISABLE_CE	0
+#define EEPROM_READ	0x80
+
+/*
+;==========================================================
+;	AMD 53C974 Registers bit Definition
+;==========================================================
+*/
+/*
+;====================
+; SCSI Register
+;====================
+*/
+
+/*; Command Reg.(+0CH) */
+#define DMA_COMMAND		BIT7
+#define NOP_CMD 		0
+#define CLEAR_FIFO_CMD		1
+#define RST_DEVICE_CMD		2
+#define RST_SCSI_BUS_CMD	3
+#define INFO_XFER_CMD		0x10
+#define INITIATOR_CMD_CMPLTE	0x11
+#define MSG_ACCEPTED_CMD	0x12
+#define XFER_PAD_BYTE		0x18
+#define SET_ATN_CMD		0x1A
+#define RESET_ATN_CMD		0x1B
+#define SELECT_W_ATN		0x42
+#define SEL_W_ATN_STOP		0x43
+#define EN_SEL_RESEL		0x44
+#define SEL_W_ATN2		0x46
+#define DATA_XFER_CMD		INFO_XFER_CMD
+
+
+/*; SCSI Status Reg.(+10H) */
+#define INTERRUPT		BIT7
+#define ILLEGAL_OP_ERR		BIT6
+#define PARITY_ERR		BIT5
+#define COUNT_2_ZERO		BIT4
+#define GROUP_CODE_VALID	BIT3
+#define SCSI_PHASE_MASK 	(BIT2+BIT1+BIT0)
+
+/*; Interrupt Status Reg.(+14H) */
+#define SCSI_RESET		BIT7
+#define INVALID_CMD		BIT6
+#define DISCONNECTED		BIT5
+#define SERVICE_REQUEST 	BIT4
+#define SUCCESSFUL_OP		BIT3
+#define RESELECTED		BIT2
+#define SEL_ATTENTION		BIT1
+#define SELECTED		BIT0
+
+/*; Internal State Reg.(+18H) */
+#define SYNC_OFFSET_FLAG	BIT3
+#define INTRN_STATE_MASK	(BIT2+BIT1+BIT0)
+
+/*; Clock Factor Reg.(+24H) */
+#define CLK_FREQ_40MHZ		0
+#define CLK_FREQ_35MHZ		(BIT2+BIT1+BIT0)
+#define CLK_FREQ_30MHZ		(BIT2+BIT1)
+#define CLK_FREQ_25MHZ		(BIT2+BIT0)
+#define CLK_FREQ_20MHZ		BIT2
+#define CLK_FREQ_15MHZ		(BIT1+BIT0)
+#define CLK_FREQ_10MHZ		BIT1
+
+/*; Control Reg. 1(+20H) */
+#define EXTENDED_TIMING 	BIT7
+#define DIS_INT_ON_SCSI_RST	BIT6
+#define PARITY_ERR_REPO 	BIT4
+#define SCSI_ID_ON_BUS		(BIT2+BIT1+BIT0)
+
+/*; Control Reg. 2(+2CH) */
+#define EN_FEATURE		BIT6
+#define EN_SCSI2_CMD		BIT3
+
+/*; Control Reg. 3(+30H) */
+#define ID_MSG_CHECK		BIT7
+#define EN_QTAG_MSG		BIT6
+#define EN_GRP2_CMD		BIT5
+#define FAST_SCSI		BIT4	/* ;10MB/SEC */
+#define FAST_CLK		BIT3	/* ;25 - 40 MHZ */
+
+/*; Control Reg. 4(+34H) */
+#define EATER_12NS		0
+#define EATER_25NS		BIT7
+#define EATER_35NS		BIT6
+#define EATER_0NS		(BIT7+BIT6)
+#define NEGATE_REQACKDATA	BIT2
+#define NEGATE_REQACK		BIT3
+/*
+;====================
+; DMA Register
+;====================
+*/
+/*; DMA Command Reg.(+40H) */
+#define READ_DIRECTION		BIT7
+#define WRITE_DIRECTION 	0
+#define EN_DMA_INT		BIT6
+#define MAP_TO_MDL		BIT5
+#define DIAGNOSTIC		BIT4
+#define DMA_IDLE_CMD		0
+#define DMA_BLAST_CMD		BIT0
+#define DMA_ABORT_CMD		BIT1
+#define DMA_START_CMD		(BIT1+BIT0)
+
+/*; DMA Status Reg.(+54H) */
+#define PCI_MS_ABORT		BIT6
+#define BLAST_COMPLETE		BIT5
+#define SCSI_INTERRUPT		BIT4
+#define DMA_XFER_DONE		BIT3
+#define DMA_XFER_ABORT		BIT2
+#define DMA_XFER_ERROR		BIT1
+#define POWER_DOWN		BIT0
+
+/*
+; DMA SCSI Bus and Ctrl.(+70H)
+;EN_INT_ON_PCI_ABORT
+*/
+
+/*
+;==========================================================
+; SCSI Chip register address offset
+;==========================================================
+*/
+#define CtcReg_Low	0x00
+#define CtcReg_Mid	0x04
+#define ScsiFifo	0x08
+#define ScsiCmd 	0x0C
+#define Scsi_Status	0x10
+#define INT_Status	0x14
+#define Sync_Period	0x18
+#define Sync_Offset	0x1C
+#define CtrlReg1	0x20
+#define Clk_Factor	0x24
+#define CtrlReg2	0x2C
+#define CtrlReg3	0x30
+#define CtrlReg4	0x34
+#define CtcReg_High	0x38
+#define DMA_Cmd 	0x40
+#define DMA_XferCnt	0x44
+#define DMA_XferAddr	0x48
+#define DMA_Wk_ByteCntr 0x4C
+#define DMA_Wk_AddrCntr 0x50
+#define DMA_Status	0x54
+#define DMA_MDL_Addr	0x58
+#define DMA_Wk_MDL_Cntr 0x5C
+#define DMA_ScsiBusCtrl 0x70
+
+#define StcReg_Low	CtcReg_Low
+#define StcReg_Mid	CtcReg_Mid
+#define Scsi_Dest_ID	Scsi_Status
+#define Scsi_TimeOut	INT_Status
+#define Intern_State	Sync_Period
+#define Current_Fifo	Sync_Offset
+#define StcReg_High	CtcReg_High
+
+#define am_target	Scsi_Status
+#define am_timeout	INT_Status
+#define am_seq_step	Sync_Period
+#define am_fifo_count	Sync_Offset
+
+
+#define DC390_read8(address)			       \
+	inb(DC390_ioport + (address)))
+
+#define DC390_read16(address)			       \
+	inw(DC390_ioport + (address)))
+
+#define DC390_read32(address)			       \
+	inl(DC390_ioport + (address)))
+
+#define DC390_write8(address,value)		       \
+	outb((value), DC390_ioport + (address)))
+
+#define DC390_write16(address,value)		       \
+	outw((value), DC390_ioport + (address)))
+
+#define DC390_write32(address,value)		       \
+	outl((value), DC390_ioport + (address)))
+
+
+/* Configuration method #1 */
+#define PCI_CFG1_ADDRESS_REG		0xcf8
+#define PCI_CFG1_DATA_REG		0xcfc
+#define PCI_CFG1_ENABLE 		0x80000000
+#define PCI_CFG1_TUPPLE(bus, device, function, register)		\
+	(PCI_CFG1_ENABLE | (((bus) << 16) & 0xff0000) | 		\
+	(((device) << 11) & 0xf800) | (((function) << 8) & 0x700)|	\
+	(((register) << 2) & 0xfc))
+
+/* Configuration method #2 */
+#define PCI_CFG2_ENABLE_REG		0xcf8
+#define PCI_CFG2_FORWARD_REG		0xcfa
+#define PCI_CFG2_ENABLE 		0x0f0
+#define PCI_CFG2_TUPPLE(function)					\
+	(PCI_CFG2_ENABLE | (((function) << 1) & 0xe))
+
+
+#endif /* TMSCSIM_H */
diff -urN linux-2.0.31-pre5/drivers/scsi/ultrastor.c linux-2.0.31-pre6/drivers/scsi/ultrastor.c
--- linux-2.0.31-pre5/drivers/scsi/ultrastor.c	1996-05-12 23:01:23.000000000 -0700
+++ linux-2.0.31-pre6/drivers/scsi/ultrastor.c	2003-08-15 15:04:01.000000000 -0700
@@ -1144,8 +1144,13 @@
     else
 	printk("US14F: interrupt: unexpected interrupt\n");
 
-    if (config.slot ? inb(config.icm_address - 1) : (inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1))
+    if (config.slot ? inb(config.icm_address - 1) :
+       (inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1))
+#if (ULTRASTOR_DEBUG & UD_MULTI_CMD)
       printk("Ux4F: multiple commands completed\n");
+#else
+      ;
+#endif
 
 #if (ULTRASTOR_DEBUG & UD_INTERRUPT)
     printk("USx4F: interrupt: returning\n");
diff -urN linux-2.0.31-pre5/fs/isofs/inode.c linux-2.0.31-pre6/fs/isofs/inode.c
--- linux-2.0.31-pre5/fs/isofs/inode.c	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/fs/isofs/inode.c	2003-08-15 15:04:01.000000000 -0700
@@ -133,13 +133,7 @@
 			  !strcmp(this_char,"uid") ||
 			  !strcmp(this_char,"gid"))) {
 		  char * vpnt = value;
-		  unsigned int ivalue;
-		  ivalue = 0;
-		  while(*vpnt){
-		    if(*vpnt <  '0' || *vpnt > '9') break;
-		    ivalue = ivalue * 10 + (*vpnt - '0');
-		    vpnt++;
-		  }
+		  unsigned int ivalue = simple_strtoul(vpnt, &vpnt, 0);
 		  if (*vpnt) return 0;
 		  switch(*this_char) {
 		  case 'b':
@@ -498,7 +492,7 @@
 	    if( (block << ISOFS_BUFFER_BITS(inode)) >= max_legal_read_offset )
 	      {
 
-		printk("_isofs_bmap: block>= EOF(%d, %d)", block, 
+		printk("_isofs_bmap: block>= EOF(%d, %ld)", block, 
 		       inode->i_size);
 	      }
 	    return 0;
diff -urN linux-2.0.31-pre5/fs/smbfs/dir.c linux-2.0.31-pre6/fs/smbfs/dir.c
--- linux-2.0.31-pre5/fs/smbfs/dir.c	1996-12-01 05:58:05.000000000 -0800
+++ linux-2.0.31-pre6/fs/smbfs/dir.c	2003-08-15 15:04:01.000000000 -0700
@@ -400,10 +400,10 @@
 
 	SMB_INOP(dir)->nused += 1;
 
-	/* We have to link the new inode_info into the doubly linked
-	   list of inode_infos to make a complete linear search
-	   possible. */
-
+	/*
+	 * We have to link the new inode_info into the doubly linked
+	 * list of inode_infos to make a complete linear search possible.
+	 */
 	root = &(SMB_SERVER(dir)->root);
 
 	new_inode_info->prev = root;
@@ -413,13 +413,15 @@
 
 	if (!(inode = iget(dir->i_sb, smb_info_ino(new_inode_info))))
 	{
-		new_inode_info->next->prev = new_inode_info->prev;
-		new_inode_info->prev->next = new_inode_info->next;
-		SMB_INOP(dir)->nused -= 1;
-
 		printk("smb_iget: iget failed!");
+		/*
+		 * If we blocked in iget(), another task may have referenced
+		 * the info structure ... clean up with smb_free_inode_info.
+		 */
+		smb_free_inode_info(new_inode_info);
 		return NULL;
 	}
+
 	return inode;
 }
 
@@ -660,13 +662,18 @@
 	{
 		goto in_tree;
 	}
+
+	if (new_inode_info == NULL)
+	{
+		iput(dir);
+		return -ENOMEM;
+	}
 	new_inode_info->finfo = finfo;
 
 	DPRINTK("attr: %x\n", finfo.attr);
 
 	if ((*result = smb_iget(dir, new_inode_info)) == NULL)
 	{
-		smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info));
 		iput(dir);
 		return -EACCES;
 	}
@@ -719,7 +726,6 @@
 
 	if ((*result = smb_iget(dir, new_inode_info)) == NULL)
 	{
-		smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info));
 		iput(dir);
 		return error;
 	}
diff -urN linux-2.0.31-pre5/fs/smbfs/inode.c linux-2.0.31-pre6/fs/smbfs/inode.c
--- linux-2.0.31-pre5/fs/smbfs/inode.c	1996-12-01 05:58:05.000000000 -0800
+++ linux-2.0.31-pre6/fs/smbfs/inode.c	2003-08-15 15:04:01.000000000 -0700
@@ -59,7 +59,8 @@
 	{
 		/* Ok, now we're in trouble. The inode info is not
 		   there. What should we do now??? */
-		printk("smb_read_inode: inode info not found\n");
+		printk("smb_read_inode: inode %ld info not found\n",
+			inode->i_ino);
 		return;
 	}
 	inode_info->state = SMB_INODE_VALID;
@@ -92,24 +93,43 @@
 static void
 smb_put_inode(struct inode *inode)
 {
-	struct smb_dirent *finfo = SMB_FINFO(inode);
 	struct smb_server *server = SMB_SERVER(inode);
 	struct smb_inode_info *info = SMB_INOP(inode);
+	struct smb_dirent *finfo;
+	__u32 mtime = inode->i_mtime;
+
+	if (inode->i_count > 1) {
+		printk("smb_put_inode: in use device %s, inode %ld count=%d\n",
+			kdevname(inode->i_dev), inode->i_ino, inode->i_count);
+		return;
+	}
 
 	if (S_ISDIR(inode->i_mode))
 	{
 		smb_invalid_dir_cache(inode->i_ino);
 	}
-	if (finfo->opened != 0)
-	{
-		if (smb_proc_close(server, finfo->fileid, inode->i_mtime))
+	clear_inode(inode);
+
+	/*
+	 * We don't want the inode to be reused as free if we block here,
+	 * so temporarily increment i_count.
+	 */
+	inode->i_count++;
+	if (info) {
+		finfo = &info->finfo;
+		if (finfo->opened != 0)
 		{
-			/* We can't do anything but complain. */
-			DPRINTK("smb_put_inode: could not close\n");
+			if (smb_proc_close(server, finfo->fileid, mtime))
+			{
+				/* We can't do anything but complain. */
+				printk("smb_put_inode: could not close\n");
+			}
 		}
-	}
-	smb_free_inode_info(info);
-	clear_inode(inode);
+		smb_free_inode_info(info);
+	} else
+		printk("smb_put_inode: no inode info??\n");
+
+	inode->i_count--;
 }
 
 static void
diff -urN linux-2.0.31-pre5/fs/smbfs/proc.c linux-2.0.31-pre6/fs/smbfs/proc.c
--- linux-2.0.31-pre5/fs/smbfs/proc.c	1996-12-30 01:51:29.000000000 -0800
+++ linux-2.0.31-pre6/fs/smbfs/proc.c	2003-08-15 15:04:01.000000000 -0700
@@ -1685,6 +1685,7 @@
 	if (server->packet != NULL)
 	{
 		smb_vfree(server->packet);
+		server->packet = NULL;
 		server->packet_size = 0;
 	}
 	server->packet = smb_vmalloc(max_xmit);
@@ -1920,6 +1921,7 @@
 
 	/* Now make a new packet with the correct size. */
 	smb_vfree(server->packet);
+	server->packet = NULL;
 
 	server->packet = smb_vmalloc(server->max_xmit);
 	if (server->packet == NULL)
diff -urN linux-2.0.31-pre5/fs/smbfs/sock.c linux-2.0.31-pre6/fs/smbfs/sock.c
--- linux-2.0.31-pre5/fs/smbfs/sock.c	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/fs/smbfs/sock.c	2003-08-15 15:04:01.000000000 -0700
@@ -338,6 +338,8 @@
 		DPRINTK("smb_receive: Increase packet size from %d to %d\n",
 			server->packet_size, len + 4);
 		smb_vfree(server->packet);
+		server->packet = NULL;
+
 		server->packet_size = 0;
 		server->packet = smb_vmalloc(len + 4);
 		if (server->packet == NULL)
diff -urN linux-2.0.31-pre5/include/asm-i386/shmparam.h linux-2.0.31-pre6/include/asm-i386/shmparam.h
--- linux-2.0.31-pre5/include/asm-i386/shmparam.h	1995-09-11 23:49:24.000000000 -0700
+++ linux-2.0.31-pre6/include/asm-i386/shmparam.h	2003-08-15 15:04:01.000000000 -0700
@@ -33,7 +33,7 @@
  * SHMMAX <= (PAGE_SIZE << _SHM_IDX_BITS).
  */
 
-#define SHMMAX 0x1000000		/* max shared seg size (bytes) */
+#define SHMMAX 0x2000000		/* max shared seg size (bytes) */
 #define SHMMIN 1 /* really PAGE_SIZE */	/* min shared seg size (bytes) */
 #define SHMMNI (1<<_SHM_ID_BITS)	/* max num of segs system wide */
 #define SHMALL				/* max shm system wide (pages) */ \
diff -urN linux-2.0.31-pre5/include/linux/kernel.h linux-2.0.31-pre6/include/linux/kernel.h
--- linux-2.0.31-pre5/include/linux/kernel.h	1996-05-20 10:33:57.000000000 -0700
+++ linux-2.0.31-pre6/include/linux/kernel.h	2003-08-15 15:04:01.000000000 -0700
@@ -68,6 +68,16 @@
  */
 #define fsuser() (current->fsuid == 0)
 
+/*
+ *      Display an IP address in readable format. 
+ */
+  
+#define NIPQUAD(addr) \
+        (((addr) >> 0)  & 0xff), \
+        (((addr) >> 8)  & 0xff), \
+        (((addr) >> 16) & 0xff), \
+        (((addr) >> 24) & 0xff)
+
 #endif /* __KERNEL__ */
 
 #define SI_LOAD_SHIFT	16
diff -urN linux-2.0.31-pre5/include/linux/proc_fs.h linux-2.0.31-pre6/include/linux/proc_fs.h
--- linux-2.0.31-pre5/include/linux/proc_fs.h	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/include/linux/proc_fs.h	2003-08-15 15:04:01.000000000 -0700
@@ -128,6 +128,7 @@
 	PROC_SCSI_QLOGICISP,
 	PROC_SCSI_SEAGATE,
 	PROC_SCSI_T128,
+	PROC_SCSI_DC390T,
 	PROC_SCSI_NCR53C7xx,
 	PROC_SCSI_NCR53C8XX,
 	PROC_SCSI_ULTRASTOR,
diff -urN linux-2.0.31-pre5/init/main.c linux-2.0.31-pre6/init/main.c
--- linux-2.0.31-pre5/init/main.c	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/init/main.c	2003-08-15 15:04:01.000000000 -0700
@@ -93,6 +93,7 @@
 extern void aic7xxx_setup(char *str, int *ints);
 extern void AM53C974_setup(char *str, int *ints);
 extern void BusLogic_Setup(char *str, int *ints);
+extern void ncr53c8xx_setup(char *str, int *ints);
 extern void eata2x_setup(char *str, int *ints);
 extern void u14_34f_setup(char *str, int *ints);
 extern void fdomain_setup(char *str, int *ints);
@@ -331,6 +332,9 @@
 #ifdef CONFIG_SCSI_BUSLOGIC
 	{ "BusLogic=", BusLogic_Setup},
 #endif
+#ifdef CONFIG_SCSI_NCR53C8XX
+	{ "ncr53c8xx=", ncr53c8xx_setup},
+#endif
 #ifdef CONFIG_SCSI_EATA
 	{ "eata=", eata2x_setup},
 #endif
diff -urN linux-2.0.31-pre5/kernel/sysctl.c linux-2.0.31-pre6/kernel/sysctl.c
--- linux-2.0.31-pre5/kernel/sysctl.c	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/kernel/sysctl.c	2003-08-15 15:04:01.000000000 -0700
@@ -139,7 +139,7 @@
 #ifdef CONFIG_ROOT_NFS
 	{KERN_NFSRNAME, "nfs-root-name", nfs_root_name, NFS_ROOT_NAME_LEN,
 	 0644, NULL, &proc_dostring, &sysctl_string },
-	{KERN_NFSRNAME, "nfs-root-addrs", nfs_root_addrs, NFS_ROOT_ADDRS_LEN,
+	{KERN_NFSRADDRS, "nfs-root-addrs", nfs_root_addrs, NFS_ROOT_ADDRS_LEN,
 	 0644, NULL, &proc_dostring, &sysctl_string },
 #endif
 #ifdef CONFIG_BINFMT_JAVA
diff -urN linux-2.0.31-pre5/net/ipv4/arp.c linux-2.0.31-pre6/net/ipv4/arp.c
--- linux-2.0.31-pre5/net/ipv4/arp.c	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/net/ipv4/arp.c	2003-08-15 15:04:01.000000000 -0700
@@ -1920,9 +1920,9 @@
 	if (tip != dev->pa_addr && net_alias_has(skb->dev)) 
 	{
 		/*
-		 *	net_alias_dev_rcv_sel32 returns main dev if it fails to found other.
+		 *	net_alias_dev_rx32 returns main dev if it fails to found other.
 		 */
-		dev = net_alias_dev_rcv_sel32(dev, AF_INET, sip, tip);
+		dev = net_alias_dev_rx32(dev, AF_INET, sip, tip);
 
 		if (dev->type != ntohs(arp->ar_hrd) || dev->flags & IFF_NOARP)
 		{
diff -urN linux-2.0.31-pre5/net/ipv4/icmp.c linux-2.0.31-pre6/net/ipv4/icmp.c
--- linux-2.0.31-pre5/net/ipv4/icmp.c	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/net/ipv4/icmp.c	2003-08-15 15:04:01.000000000 -0700
@@ -749,7 +749,7 @@
 				break;
 		}
 		if(icmph->code>NR_ICMP_UNREACH)	/* Invalid type */
-			return;
+			goto flush_it;
 	}
 	
 	/*
diff -urN linux-2.0.31-pre5/net/ipv4/ip_input.c linux-2.0.31-pre6/net/ipv4/ip_input.c
--- linux-2.0.31-pre5/net/ipv4/ip_input.c	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/net/ipv4/ip_input.c	2003-08-15 15:04:01.000000000 -0700
@@ -297,13 +297,13 @@
 
 	/*
 	 *	Try to select closest <src,dst> alias device, if any.
-	 *	net_alias_dev_rcv_sel32 returns main device if it 
+	 *	net_alias_dev_rx32 returns main device if it 
 	 *	fails to found other.
 	 */
 
 #ifdef CONFIG_NET_ALIAS
 	if (iph->daddr != skb->dev->pa_addr && net_alias_has(skb->dev)) {
-		skb->dev = dev = net_alias_dev_rcv_sel32(skb->dev, AF_INET, iph->saddr, iph->daddr);
+		skb->dev = dev = net_alias_dev_rx32(skb->dev, AF_INET, iph->saddr, iph->daddr);
 	}
 #endif
 
diff -urN linux-2.0.31-pre5/net/ipv4/tcp_input.c linux-2.0.31-pre6/net/ipv4/tcp_input.c
--- linux-2.0.31-pre5/net/ipv4/tcp_input.c	2003-08-15 15:04:01.000000000 -0700
+++ linux-2.0.31-pre6/net/ipv4/tcp_input.c	2003-08-15 15:04:01.000000000 -0700
@@ -618,7 +618,8 @@
 			/* Only let this warning get printed once a minute. */
 			if (jiffies - warning_time > HZ*60) {
 				warning_time = jiffies;
-				printk(KERN_INFO "Warning: possible SYN flooding on port %d. Sending cookies.\n", ntohs(th->dest));
+				printk(KERN_INFO "Warning: possible SYN flood from %d.%d.%d.%d on %d.%d.%d.%d:%d.  Sending cookies.\n", 
+					NIPQUAD(saddr), NIPQUAD(daddr), ntohs(th->dest));
 			}
 #ifdef CONFIG_RST_COOKIES
 			tcp_send_synack_probe(daddr, saddr, th, &tcp_prot,
diff -urN linux-2.0.31-pre5/scripts/ksymoops.cc linux-2.0.31-pre6/scripts/ksymoops.cc
--- linux-2.0.31-pre5/scripts/ksymoops.cc	1996-04-08 21:07:40.000000000 -0700
+++ linux-2.0.31-pre6/scripts/ksymoops.cc	2003-08-15 15:04:01.000000000 -0700
@@ -31,6 +31,7 @@
 // * Only resolves operands of jump and call instructions.
 
 #include <fstream.h>
+#include <strstream.h>
 #include <iomanip.h>
 #include <stdio.h>
 #include <string.h>
@@ -184,9 +185,23 @@
     
     char buf[1024];
     int lines = 0;
+    int eip_seen = 0;
+    long offset;
     while (fgets(buf, sizeof(buf), objdump_FILE)) {
+	if (eip_seen && buf[4] == ':') {
+	    // assume objdump from binutils 2.8..., reformat to old style
+	    offset = strtol(buf, 0, 16);
+	    char newbuf[sizeof(buf)];
+	    memset(newbuf, '\0', sizeof(newbuf));
+	    ostrstream ost(newbuf, sizeof(newbuf));
+	    ost.width(8);
+	    ost << offset;
+	    ost << " <_EIP+" << offset << ">: " << &buf[6] << ends;
+	    strcpy(buf, newbuf);
+	}
 	if (!strnequ(&buf[9], "<_EIP", 5))
 	    continue;
+	eip_seen = 1;
 	if (strstr(buf, " is out of bounds"))
 	    break;
 	lines++;
@@ -195,19 +210,28 @@
 	    cout << buf;
 	    continue;
 	}
-	long offset = strtol(buf, 0, 16);
-	char* bp_0 = strchr(buf, '>') + 2;
+	offset = strtol(buf, 0, 16);
+	char* bp_0 = strchr(buf, '>');
 	KSym* ksym = find(eip_addr + offset);
+	if (bp_0)
+	    bp_0 += 2;
+	else
+	    bp_0 = strchr(buf, ':');
 	if (ksym)
 	    cout << *ksym << ' ';
-	char* bp = bp_0;
+	char *bp_1 = strstr(bp_0, "\t");        // objdump from binutils 2.8...
+	if (bp_1)
+	    ++bp_1;
+	else
+	    bp_1 = bp_0;
+	char *bp = bp_1;
 	while (!isspace(*bp))
 	    bp++;
 	while (isspace(*bp))
 	    bp++;
-	if (*bp != '0') {
+	if (!isxdigit(*bp)) {
 	    cout << bp_0;
-	} else if (*bp_0 == 'j' || strnequ(bp_0, "call", 4)) { // a jump or call insn
+	} else if (*bp_1 == 'j' || strnequ(bp_1, "call", 4)) { // a jump or call insn
 	    long rel_addr = strtol(bp, 0, 16);
 	    ksym = find(eip_addr + rel_addr);
 	    if (ksym) {
