diff -u --recursive --new-file v2.0.2/linux/CREDITS linux/CREDITS
--- v2.0.2/linux/CREDITS	Sat Jul  6 12:07:12 1996
+++ linux/CREDITS	Sat Jul  6 11:59:56 1996
@@ -1182,6 +1182,16 @@
 S: Beaverton, OR 97008
 S: USA
 
+N: Mike Shaver
+E: shaver@ingenia.com
+W: http://neon.ingenia.com/~shaver/
+D: Network hacking, /proc/sys/net
+S: c/o Ingenia Communications Corporation
+S: Suite 4200, CTTC Building
+S: 1125 Colonel By Drive
+S: Ottawa, Ontario, Canada
+S: K1S 5R1
+
 N: John Shifflett
 E: john@geolog.com
 E: jshiffle@netcom.com
diff -u --recursive --new-file v2.0.2/linux/Documentation/Changes linux/Documentation/Changes
--- v2.0.2/linux/Documentation/Changes	Sat Jul  6 12:07:12 1996
+++ linux/Documentation/Changes	Sat Jul  6 11:59:56 1996
@@ -3,7 +3,7 @@
 
 This document contains a list of the latest releases of the most
 important packages for Linux as well as instructions for newcomers to
-the 1.3.x series of kernels.  By glancing through it, you should be
+the 2.0.x series of kernels.  By glancing through it, you should be
 able to find out what you need to upgrade in order to successfully run
 the latest kernels.
 
@@ -18,13 +18,17 @@
 Taylor.  Check out http://www.cviog.uga.edu/LinuxBleed.html if you
 prefer a HTML-ized shopping list.
 
-Last updated: June 6, 1996.
+   Para aquellos que prefieran una version en castellano de este
+documento, consultad la traduccion de Alfredo Sanjuan en
+http://slug.ctv.es/~alfredo/Cambios.html.
+
+Last updated: July 6, 1996.
 Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
 
 Current Releases
 ****************
 
-- Kernel modules	 Stable: 1.3.57, Exp: 1.3.69k
+- Kernel modules	 2.0.0
 - PPP daemon		 Stable: 2.2.0f
 - Dynamic linker (ld.so) 1.7.14
 - GNU CC		 2.7.2
@@ -32,9 +36,9 @@
 - Linux C Library	 Stable:  5.2.18, Beta:  5.3.12
 - Linux C++ Library	 2.7.1.4
 - Termcap		 2.0.8
-- Procps		 0.99a
+- Procps		 1.01
 - Gpm			 1.09
-- SysVinit		 2.62
+- SysVinit		 2.64
 - Util-linux		 2.5
 
 Upgrade notes
@@ -58,14 +62,15 @@
 Booting Changes
 ===============
 
-   The boot stuff in 1.3.x (for arch/i386) has been enhanced so that it
-now can load bigger kernels (bzImage) and that the loaders now can load
-an initial ramdisk (initrd). For initrd see Documentation/initrd.txt.
-For building bigger kernels use one of the following make targets:
-bzImage, bzlilo, bzdisk (equivalent to make targets zImage, zlilo, and
-zdisk respectively).  If you want or need to use the new features
-you'll need to upgrade your bootloaders.  Lilo can be found at
-ftp://lrcftp.epfl.ch/pub/linux/local/lilo/lilo.19.tar.gz.  LOADLIN is at
+   The boot support in 2.0.x (for arch/i386) has been enhanced so that
+it now can load bigger kernels (bzImage) and that the loaders now can
+load an initial ramdisk (initrd). For initrd see
+Documentation/initrd.txt. For building bigger kernels use one of the
+following make targets: bzImage, bzlilo, bzdisk (equivalent to make
+targets zImage, zlilo, and zdisk respectively). If you want or need to
+use the new features you'll need to upgrade your bootloaders.  Lilo can
+be found at ftp://lrcftp.epfl.ch/pub/linux/local/lilo/lilo.19.tar.gz.
+LOADLIN is at
 ftp://sunsite.unc.edu/pub/Linux/system/Linux-boot/lodlin16.tgz.  If
 you're using more unusual loaders like SysLinux or etherboot, the
 latest versions are 1.3 and 2.0, respectively.
@@ -82,7 +87,7 @@
 release there are some important changes that may cause troubles to
 buggy programs (programs that call free() on a pointer not returned by
 malloc() work with previous libc, but not with this release) so read the
-`release.libc-5.3.9' file carefully!  In the latest libc releases a
+`release.libc-5.3.12' file carefully!  In the latest libc releases a
 dirent bug, which erroneously defined d->reclen to d->namlen if USE_GNU
 was defined, has been fixed.  Unfortunately, some GNU packages depend
 on this bug.  GNU make 3.xx is one of them.  To fix that you need to
@@ -98,10 +103,10 @@
 
    `fcntl_setlk() called by process 123 with broken flock() emulation'
 
-   then you need to upgrade to libc-5.2.18 as well.  A proper (in other
-words, BSD-style ;-) flock system call was added in 1.3.x, and older
-libc's will now give this error.  It doesn't *really* matter, so you
-can just ignore it.  If it really annoys you, upgrade libc (and
+   then you need to upgrade to at least libc-5.2.18 as well.  A proper
+(in other words, BSD-style ;-) flock system call was added to 2.0.x,
+and older libc's will now give this error.  It doesn't *really* matter,
+so you can just ignore it. If it really annoys you, upgrade libc (and
 recompile any static binaries you might have that are linked against
 the old libc).  If you're feeling lazy, just comment out
 
@@ -123,32 +128,27 @@
 Procps utilities
 ================
 
-   In the latest 1.3.x kernel releases the /proc file system structure
-was changed, so you need to upgrade the procps package to version
-0.99a.  In the very latest kernels, /proc has changed again.  There's
-not yet an officially updated version of procps, so use 0.99a; you
-might want to look for one of the patches floating around to update
-0.99a for use with 1.3.94 and later kernels.
+   Due to changes in the structure of the /proc filesystem, you need to
+upgrade procps to the latest release, currently 1.01.  Otherwise,
+you'll get floating point errors with some ps commands or other similar
+surprises.
 
 Kernel Modules
 ==============
 
-   1.3.x is almost completely modularized, and kerneld is now
+   Almost all drivers in 2.0.x can be modules, and kerneld is now
 incorporated into the kernel.  To take advantage of this, you'll need
-the latest version of the module support apps.  The latest non-beta is
-modules-1.3.57.tar.gz, and the latest beta is modules-1.3.69k.tar.gz.
-These should be available at the same place you picked up your kernel
-(ftp://ftp.funet.fi/pub/Linux/kernel/src/) and the home page is
-http://www.pi.se/blox/modules/index.html.  Note:  If you try to load a
+the latest version of the module support apps, currently 2.0.0. These
+should be available at the same place you picked up your kernel
+(ftp://ftp.funet.fi/pub/Linux/kernel/src/) or the home page,
+http://www.pi.se/blox/modules/index.html.  Note: If you try to load a
 module and get a message like
 
    `gcc2_compiled, undefined Failed to load module!  The symbols from
 kernel 1.3.foo don't match 1.3.foo'
 
-   where `foo' is a number for a recent kernel, then it's time to
-upgrade module utilities from 1.3.57 to the latest beta 1.3.69; you'll
-only get this error if you're running the latest binutils, so most
-people don't need to upgrade past 1.3.57.
+   where `foo' is a number for a recent kernel, then it's definitely
+time to upgrade module utilities.
 
    Another little tip: you can't have both a.out *and* ELF support
 compiled as modules.  Otherwise, you get a nice Catch-22 when you try
@@ -160,7 +160,7 @@
 have to mount at startup have to have their necessary file system and
 device drivers compiled into the kernel, so don't get grandiose ideas
 about going completely modular and then forget to compile ext2fs
-support and ide drive support into your kernel ;-).
+support and ide/SCSI drive support into your kernel ;-).
 
 PPP driver
 ==========
@@ -179,13 +179,11 @@
 your computer shuts down fine but "INIT: error reading initrequest" or
 words to that effect scroll across your screen hundreds of times.  To
 fix, upgrade to
+ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.64.tar.gz.
 
-ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.64.tar.gz or
-ftp://tsx-11.mit.edu /pub/linux/sources/sbin/sysvinit-2.64.tar.gz
-
-   If you're trying to run NCSA httpd, you have to set pre-spawning of
-daemons to zero, as it incorrectly assumes SunOS behavior.  I recommend
-you just switch to Apache httpd.
+   If you're trying to run NCSA httpd, you might have problems with
+pre-spawning daemons.  Upgrade to the latest release (1.5.2), available
+from http://hoohoo.ncsa.uiuc.edu/.
 
    The new named pipe behavior also causes problems with Hylafax.  If
 you're running the hylafax daemon, it will just keep eating up CPU time
@@ -251,7 +249,7 @@
 
    Hdparm has been upgraded to take advantage of the latest features of
 the kernel drivers.  The latest non-beta version can be found at
-ftp://sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/hdparm-2.7.tar.gz.
+ftp://sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/hdparm-2.9.tar.gz.
 
 IP Accounting
 =============
@@ -271,13 +269,13 @@
 IP Firewalls
 ============
 
-   The IP firewall code has been changed drastically during 1.3.x.
-There are now 3 categories of firewall rules: one for incoming packets,
-one for outgoing packets, and one for packets being forwarded.  There
-also exists a possibility to match on device names and/or device
-addresses, so that only packets coming in/going out via that device
-(network interface) match with a rule.  This is especially useful to
-prevent spoofing.  You'll need to get
+   The IP firewall code has been changed drastically for 2.0.x. There
+are now 3 categories of firewall rules: one for incoming packets, one
+for outgoing packets, and one for packets being forwarded.  There also
+exists a possibility to match on device names and/or device addresses,
+so that only packets coming in/going out via that device (network
+interface) match with a rule.  This is especially useful to prevent
+spoofing.  You'll need to get
 ftp://ftp.xos.nl/pub/linux/ipfwadm/ipfwadm-2.1.tar.gz to use this.
 
 IP Masquerading
@@ -296,20 +294,12 @@
 ftp://ftp.franken.de/pub/isdn4linux/isdn4k-utils-1.3.97.tar.gz to try
 this.
 
-Term is broken
-==============
-
-   Term (a comm line multiplexer similar in purpose to slirp) does not
-work with kernels later than 1.3.60.  Since the author of term is
-apparently currently on vacation, there is no fix forthcoming.  I
-suggest that those of you who rely on term learn to use slirp.
-
 Networking
 ==========
 
    Some of the /proc/net entries have changed.  You'll need to upgrade
 to the latest net-tools in
-ftp://ftp.inka.de:/pub/comp/Linux/networking/net-tools.  The last
+ftp://ftp.inka.de/pub/comp/Linux/networking/net-tools.  The last
 official release there is net-tools-1.2.0.tar.gz, and the latest
 release is net-tools-1.32-alpha.tar.gz.  If you need the upgrade, you
 probably need the latest beta release.
@@ -354,12 +344,12 @@
 Loop device
 ===========
 
-   1.3.x kernels include loop device support which lets you mount a
+   2.0.x kernels include loop device support which lets you mount a
 file as a file system, which can allow for all sorts of cool things
 like encrypted file systems and such.  To use it, you'll need a
 modified version of mount from
-ftp://ftp.win.tue.nl/pub/linux/util/mount-2.5X.tar.gz and preliminary
-work on encrypted file system support can be found in
+ftp://ftp.win.tue.nl/pub/linux/util/mount-2.5X.tar.gz; preliminary work
+on encrypted file system support can be found in
 ftp.funet.fi:/pub/OS/Linux/BETA/loop/des.1.tar.gz.
 
 Multiple device
@@ -380,11 +370,10 @@
 Quota
 =====
 
-   Quota support has also been added.  You need to get quotas-1.51 from
+   Quota support has also been added.  You need to get quotas-1.55 from
 ftp://ftp.funet.fi/pub/Linux/PEOPLE/Linus/subsystems/quota/all.tar.gz.
-This will compile just fine after you copy its mntent.h over to
-/usr/include/mntent.h.  I've uploaded this to sunsite as
-ftp://sunsite.unc.edu/pub/Linux/system/Admin/quotas-1.51-tar.gz
+You may need to copy its mntent.h over to /usr/include/mntent.h to get
+it to compile.
 
 Process Accounting
 ==================
@@ -398,7 +387,8 @@
 
    Bdflush has also been integrated into the new kernels, so those of
 you using it on older systems no longer need to hunt for the patches to
-implement it once you upgrade to 1.3.x.
+implement it once you upgrade to 2.0.x.  You do still need to run the
+update daemon, however.
 
 APM support
 ===========
@@ -412,19 +402,20 @@
 iBCS and Dosemu
 ===============
 
-   For a version of iBCS that works with 1.3.x kernels, grab
-ftp://tsx-11.mit.edu/pub/linux/BETA/ibcs2/ibcs-1.3-960404-ALPHA.tar.gz
+   For a version of iBCS that works with 2.0.x kernels, grab
+ftp://tsx-11.mit.edu/pub/linux/BETA/ibcs2/ibcs-2.0-960610.tar.gz
 
    For a version of Dosemu that works (well, at least as well as DOS
 ever works ;-), get
-ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/Development/dosemu-0.63.1.19.tgz.
-Be sure to follow the instructions in README.newkernels about patching
-your include files, or it will not compile.
+ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/Development/dosemu-0.63.1.36.tgz
+or check out http://www.ednet.ns.ca/auto/rddc. Be sure to follow the
+instructions in README.newkernels about patching your include files, or
+it will not compile.
 
 Mtools and Fdutils
 ==================
 
-   The floppy ioctl numbering scheme has changed in 1.3.x.  For
+   The floppy ioctl numbering scheme has changed for 2.0.x.  For
 backwards compatibility, the old system was supported through 1.3.x and
 will generate a warning in 2.0.  In 2.1.x, the old scheme will
 disappear entirely.
@@ -439,6 +430,36 @@
    In the future, fdformat might disappear entirely, so get used to
 using superformat instead.
 
+NCR 83c510 SCSI Driver
+======================
+
+   Drivers for this card are now included in the standard linux source.
+However, they require Perl to be installed before they will compile.
+As far as I know, this is the only code in the kernel source that
+requires Perl to compile.  If your kernel compile fails and you happen
+to have included this driver in your configuration, make sure you have
+Perl installed.
+
+Perl
+====
+
+   While we're on the subject, changes made for the 2.0.x series cause
+the connect() Perl (both 4 and 5) call to time out while connecting to
+remote systems.  If you need the connect call for your program, use C
+instead of Perl.
+
+   Also, Perl scripts using the readdir call now misbehave if you're
+using an old version of Perl, due to changes in libc.  Upgrade to a
+more current Perl to avoid any unpleasantness.
+
+groff
+=====
+
+   Those of you running Slackware may experience weirdness with man
+pages due to changes in groff.  If your man pages display <AD> for -
+when present at the end of a line, try adding a -r to your LESS
+environmental variable.
+
 How to know the version of the installed programs
 *************************************************
 
@@ -493,14 +514,12 @@
 Linux C++ Library
 =================
 
-ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.1.3.bin.tar.gz
 ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.1.4.bin.tar.gz
-
-Use libc5.2.18 with 2.7.1.3, libc5.3.12 with 2.7.1.4
-
+ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.1.3.bin.tar.gz
 Installation notes:
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.1.3
 ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.1.4
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.1.3
+Use 2.7.13 with libc 5.2.18 and 2.7.14 with libc 5.3.12.
 
 Dynamic Linker
 ==============
@@ -516,9 +535,7 @@
 =================
 
 The latest public release:
-ftp://sunsite.unc.edu/pub/Linux/kernel/modules-1.3.57.tar.gz
-The latest experimental release:
-http://www.pi.se/blox/
+ftp://sunsite.unc.edu/pub/Linux/kernel/modules-2.0.0.tar.gz
 
 PPP Daemon and utilities
 ========================
@@ -529,7 +546,7 @@
 Procps utilities
 ================
 
-ftp://sunsite.unc.edu/pub/Linux/system/Status/ps/procps-0.99a.tgz
+ftp://sunsite.unc.edu/pub/Linux/system/Status/ps/procps-1.01.tgz
 
 Gpm mouse utilities
 ===================
@@ -540,7 +557,7 @@
 SysVinit utilities
 ==================
 
-ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.62.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.64.tar.gz
 
 Util-linux
 ==========
@@ -568,10 +585,12 @@
 distribution), most of these are available in RPM format.  Check around
 your favorite Red Hat mirror site before installing the non-RPM
 version.  Remember, you might need to use the -force option to get the
-upgrade to install.
+upgrade to install.  Almost everything you need is available in
+ftp://ftp.redhat.com/pub/current/i386/updates/2.0-kernel/ and its
+mirrors.
 
-Please send info about any other packages that 1.3.x "broke" or about
-any new features of 1.3.x that require extra or new packages for use to
+Please send info about any other packages that 2.0.x "broke" or about
+any new features of 2.0.x that require extra or new packages for use to
 Chris Ricker (gt1355b@prism.gatech.edu).  I generate this from a
 modified texinfo setup, so you don't need to bother generating a diff
 against the current version before you send the additional information
diff -u --recursive --new-file v2.0.2/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.0.2/linux/Documentation/Configure.help	Sun Jun  9 13:28:41 1996
+++ linux/Documentation/Configure.help	Sat Jul  6 12:06:37 1996
@@ -1433,6 +1433,81 @@
   will cause your SCSI system to hang, which might cause a system crash. 
   The safe answer therefore is to say N.
 
+NCR53C8XX SCSI support
+CONFIG_SCSI_NCR53C8XX
+  This is the BSD ncr driver adapted to linux for NCR53C8XX family of PCI-SCSI 
+  controllers. This driver supports parity checking, tagged command queueing,
+  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.
+
+force normal IO
+CONFIG_SCSI_NCR53C8XX_IOMAPPED
+  This option allow to force the driver to use normal IO.
+  Memory mapped IO have less latency than normal IO.
+  During initialisation 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.
+  The normal answer therefore is N.
+
+not allow targets to disconnect
+CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
+  This option is only provided for safe if you suspect some scsi device 
+  of yours to not support properly this feature.
+  To not allow targets to disconnect is not reasonnable if there is more 
+  than 1 device on a scsi bus.
+  The normal answer therefore is N.
+
+enable tagged command queueing
+CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE
+  This option allow to enable tagged command queuing support at linux start-up.
+  Some scsi devices do not support properly this feature.
+  The suggested method may be to not validate this option in the configuration 
+  but to use the "settags" control command after boot-up to enable this feature.
+      echo "settags 2 4" >/proc/scsi/ncr53c8xx/0
+  Ask the driver to use up to 4 concurrent tagged commands for target 2 of 
+  controller 0.
+  See the README.ncr53c8xx file for more information.
+  WARNING! tagged queue support requires to allow targets to disconnect.
+  The safe answer therefore is N.
+  The normal answer therefore is Y.
+
+force asynchronous transfer mode
+CONFIG_SCSI_NCR53C8XX_FORCE_ASYNCHRONOUS
+  This option allow 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
+  Ask the driver to set the period to 25 ns (10MB/sec) for target 2 of 
+  controller 0.
+  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.
+
 Always IN2000 SCSI support
 CONFIG_SCSI_IN2000
   This is support for an ISA bus SCSI host adaptor. You'll find
diff -u --recursive --new-file v2.0.2/linux/Makefile linux/Makefile
--- v2.0.2/linux/Makefile	Sat Jul  6 12:07:12 1996
+++ linux/Makefile	Sat Jul  6 12:13:06 1996
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 0
-SUBLEVEL = 2
+SUBLEVEL = 3
 
 ARCH = i386
 
diff -u --recursive --new-file v2.0.2/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c
--- v2.0.2/linux/drivers/cdrom/sbpcd.c	Sun Jun  9 13:28:42 1996
+++ linux/drivers/cdrom/sbpcd.c	Sat Jul  6 11:59:56 1996
@@ -461,8 +461,8 @@
 #if 0
 static void mark_timeout_audio(u_long);
 #endif
-static void sbp_read_cmd(void);
-static int sbp_data(void);
+static void sbp_read_cmd(struct request *req);
+static int sbp_data(struct request *req);
 static int cmd_out(void);
 static int DiskInfo(void);
 static int sbpcd_chk_disk_change(kdev_t);
@@ -4428,23 +4428,55 @@
 /*
  *  Take care of the different block sizes between cdrom and Linux.
  */
-static void sbp_transfer(void)
+static void sbp_transfer(struct request *req)
 {
 	long offs;
 	
-	while ( (CURRENT->nr_sectors > 0) &&
-	       (CURRENT->sector/4 >= D_S[d].sbp_first_frame) &&
-	       (CURRENT->sector/4 <= D_S[d].sbp_last_frame) )
-	{
-		offs = (CURRENT->sector - D_S[d].sbp_first_frame * 4) * 512;
-		memcpy(CURRENT->buffer, D_S[d].sbp_buf + offs, 512);
-		CURRENT->nr_sectors--;
-		CURRENT->sector++;
-		CURRENT->buffer += 512;
+	while ( (req->nr_sectors > 0) &&
+	       (req->sector/4 >= D_S[d].sbp_first_frame) &&
+	       (req->sector/4 <= D_S[d].sbp_last_frame) )
+	{
+		offs = (req->sector - D_S[d].sbp_first_frame * 4) * 512;
+		memcpy(req->buffer, D_S[d].sbp_buf + offs, 512);
+		req->nr_sectors--;
+		req->sector++;
+		req->buffer += 512;
 	}
 }
 /*==========================================================================*/
 /*
+ *  special end_request for sbpcd to solve CURRENT==NULL bug. (GTL)
+ *
+ *  This is a kluge so we don't need to modify end_request
+ *  We put the req we take out after INIT_REQUEST in the requests list,
+ *  so that end_request will discard it. 
+ *
+ *  The bug could be present in other block devices, perhaps we
+ *  should modify INIT_REQUEST and end_request instead, and
+ *  change every block device.. 
+ *
+ *  Could be a race here?? Could e.g. a timer interrupt schedule() us?
+ *  If so, we should copy end_request here, and do it right.. (or
+ *  modify end_request and the block devices.
+ *
+ *  In any case, the race here would be much small than it was, and
+ *  I couldn't reproduce..
+ *
+ *  The race could be: suppose CURRENT==NULL. We put our req in the list,
+ *  and we are scheduled. Other process takes over, and gets into
+ *  do_sbpcd_request. It sees CURRENT!=NULL (it is == to our req), so
+ *  proceds. It ends, so CURRENT is now NULL.. Now we awake somewhere in
+ *  end_request, but now CURRENT==NULL... oops!
+ *
+ */
+#undef DEBUG_GTL
+static inline void sbpcd_end_request(struct request *req, int uptodate) {
+	req->next=CURRENT;
+	CURRENT=req;
+	end_request(uptodate);
+}
+/*==========================================================================*/
+/*
  *  I/O request routine, called from Linux kernel.
  */
 static void DO_SBPCD_REQUEST(void)
@@ -4452,27 +4484,48 @@
 	u_int block;
 	u_int nsect;
 	int i, status_tries, data_tries;
-	
+	struct request *req;
+#ifdef DEBUG_GTL
+	static int xx_nr=0;
+	int xnr;
+#endif
+
  request_loop:
-	INIT_REQUEST;
-	sti();
-	
-	if ((CURRENT == NULL) || CURRENT->rq_status == RQ_INACTIVE) {
+#ifdef DEBUG_GTL
+	xnr=++xx_nr;
+
+	if(!CURRENT)
+	{
+		printk( "do_sbpcd_request[%di](NULL), Pid:%d, Time:%li\n",
+			xnr, current->pid, jiffies);
+		printk( "do_sbpcd_request[%do](NULL) end 0 (null), Time:%li\n",
+			xnr, jiffies);
 		CLEAR_INTR;
 		return;
 	}
-	if (CURRENT -> sector == -1)
+
+	printk(" do_sbpcd_request[%di](%p:%ld+%ld), Pid:%d, Time:%li\n",
+		xnr, CURRENT, CURRENT->sector, CURRENT->nr_sectors, current->pid, jiffies);
+#endif
+	INIT_REQUEST;
+	req=CURRENT;		/* take out our request so no other */
+	CURRENT=req->next;	/* task can fuck it up         GTL  */
+	sti();
+	
+	if (req->rq_status == RQ_INACTIVE)
+		goto err_done;
+	if (req -> sector == -1)
 		goto err_done;
-	if (CURRENT->cmd != READ)
+	if (req->cmd != READ)
 	{
-		msg(DBG_INF, "bad cmd %d\n", CURRENT->cmd);
+		msg(DBG_INF, "bad cmd %d\n", req->cmd);
 		goto err_done;
 	}
-	i = MINOR(CURRENT->rq_dev);
+	i = MINOR(req->rq_dev);
 	if ( (i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1))
 	{
 		msg(DBG_INF, "do_request: bad device: %s\n",
-			kdevname(CURRENT->rq_dev));
+			kdevname(req->rq_dev));
 		goto err_done;
 	}
 	while (busy_audio) sbp_sleep(HZ); /* wait a bit */
@@ -4481,19 +4534,23 @@
 	if (D_S[i].audio_state==audio_playing) goto err_done;
 	if (d!=i) switch_drive(i);
 	
-	block = CURRENT->sector; /* always numbered as 512-byte-pieces */
-	nsect = CURRENT->nr_sectors; /* always counted as 512-byte-pieces */
+	block = req->sector; /* always numbered as 512-byte-pieces */
+	nsect = req->nr_sectors; /* always counted as 512-byte-pieces */
 	
 	msg(DBG_BSZ,"read sector %d (%d sectors)\n", block, nsect);
 #if 0
 	msg(DBG_MUL,"read LBA %d\n", block/4);
 #endif
 	
-	sbp_transfer();
+	sbp_transfer(req);
 	/* if we satisfied the request from the buffer, we're done. */
-	if (CURRENT->nr_sectors == 0)
+	if (req->nr_sectors == 0)
 	{
-		end_request(1);
+#ifdef DEBUG_GTL
+		printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 2, Time:%li\n",
+			xnr, req, req->sector, req->nr_sectors, jiffies);
+#endif
+		sbpcd_end_request(req, 1);
 		goto request_loop;
 	}
 
@@ -4521,21 +4578,29 @@
 			break;
 		}
 		
-		sbp_read_cmd();
+		sbp_read_cmd(req);
 		sbp_sleep(0);
-		if (sbp_data() != 0)
+		if (sbp_data(req) != 0)
 		{
 #if SAFE_MIXED
 			D_S[d].has_data=2; /* is really a data disk */
 #endif SAFE_MIXED
-			end_request(1);
+#ifdef DEBUG_GTL
+			printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 3, Time:%li\n",
+				xnr, req, req->sector, req->nr_sectors, jiffies);
+#endif
+			sbpcd_end_request(req, 1);
 			goto request_loop;
 		}
 	}
 	
  err_done:
 	busy_data=0;
-	end_request(0);
+#ifdef DEBUG_GTL
+	printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 4 (error), Time:%li\n",
+		xnr, req, req->sector, req->nr_sectors, jiffies);
+#endif
+	sbpcd_end_request(req, 0);
 	sbp_sleep(0);    /* wait a bit, try again */
 	goto request_loop;
 }
@@ -4543,7 +4608,7 @@
 /*
  *  build and send the READ command.
  */
-static void sbp_read_cmd(void)
+static void sbp_read_cmd(struct request *req)
 {
 #undef OLD
 
@@ -4552,7 +4617,7 @@
 	
 	D_S[d].sbp_first_frame=D_S[d].sbp_last_frame=-1;      /* purge buffer */
 	D_S[d].sbp_current = 0;
-	block=CURRENT->sector/4;
+	block=req->sector/4;
 	if (block+D_S[d].sbp_bufsiz <= D_S[d].CDsize_frm)
 		D_S[d].sbp_read_frames = D_S[d].sbp_bufsiz;
 	else
@@ -4650,7 +4715,7 @@
  *  Check the completion of the read-data command.  On success, read
  *  the D_S[d].sbp_bufsiz * 2048 bytes of data from the disk into buffer.
  */
-static int sbp_data(void)
+static int sbp_data(struct request *req)
 {
 	int i=0, j=0, l, frame;
 	u_int try=0;
@@ -4913,9 +4978,9 @@
 		return (0);
 	}
 	
-	D_S[d].sbp_first_frame = CURRENT -> sector / 4;
+	D_S[d].sbp_first_frame = req -> sector / 4;
 	D_S[d].sbp_last_frame = D_S[d].sbp_first_frame + D_S[d].sbp_read_frames - 1;
-	sbp_transfer();
+	sbp_transfer(req);
 	return (1);
 }
 /*==========================================================================*/
diff -u --recursive --new-file v2.0.2/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx
--- v2.0.2/linux/drivers/scsi/ChangeLog.ncr53c8xx	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/ChangeLog.ncr53c8xx	Sat Jul  6 12:06:37 1996
@@ -0,0 +1,613 @@
+Mon Jul 03  23:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	Release 1.12a
+	Tested linux releases: 1.2.13, 2.0.0, 2.0.1
+
+Mon Jul 01  21:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	ncr53c8xx.h, ncr53c8xx.c
+	Add "clearprof" user command that clear the profile counters.
+	Automatically clear profile counters when num_kbytes=1000000000 
+	in order to avoid ugly overflow.
+	Donnot compile user command code and profile data with 1.2.13.
+
+Wed Jun 29  20:38 1996 Gerard Roudier (groudier@club-internet.fr)
+	Matthew Geier reported to me a weird problem of unexpected 
+	disconnection while asynchronous negotiation.
+	The message sent by the driver is 1-3-1-ff-00. I sent a patch to 
+	Matthew that change the message to 1-3-1-00-00.
+	The sync msgout was correct however some devices might be to happy 
+	with ff.
+
+Wed Jun 26  22:57 1996 Gerard Roudier (groudier@club-internet.fr)
+	Patch no 4 sent to Harald.
+	The drived used "wtime" for timeouts adn time measurements.
+	I change for jiffies.
+	Work with my P133.
+
+Mon Jun 24  23:05 1996 Gerard Roudier (groudier@club-internet.fr)
+	Patch no 3 sent to Harald.
+
+Sun Jun 23  22:29 1996 Gerard Roudier (groudier@club-internet.fr)
+	Patch no 2 sent to Harald.
+	I think that the driver have some chance to work.
+	
+Sun Jun 23  15:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	Harald Koenig is interested in the adaptation of the driver to 
+	Linux/Alpha.
+	I have prepared a patch and sent it to Harald.
+
+Sun Jun 16  19:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	Release 1.11
+	Tested linux releases: 1.2.13, 2.0.0
+
+Sat Jun 15 23:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.h, Configure.help, scsi/Config.in
+	Add CONFIG_SCSI_NCR53C8XX_IOMAPPED config option.
+	Prepare the 2.0.0 with the new version of the driver.
+
+Wed Jun 12 23:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	Rewrite the README file.
+	Add some documentations of the proc file system support.
+
+Sun Jun 9 18:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	Add proc filesystem support of the driver.
+	Read operations returns profile information.
+	Write operations send control commands to the host adapter driver.
+
+Wed Jun 5 22:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	Change xfer direction for SCAN command to write.
+	Was bogus.
+
+Tue May 30 18:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	Set the DMA FIFO to 88 for 825A and 875 boards.
+	The previous value of 536 is bogus since the script only read 7 
+	bits for the fifo size (thanks to Stefan).
+
+Mon May 27 18:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	Correct the xfer direction guessing for scanner SCAN command (write).
+
+Mon May 27 18:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	Add the following config options:
+	SCSI_NCR_DISABLE_MPARITY_CHECK : disable master parity checking.
+	SCSI_NCR_DISABLE_PARITY_CHECK  : disable scsi parity checking.
+	SCSI_NCR_FORCE_SYNC_NEGO       : force sync nego for all scsi 2 devices.
+
+Sat May 25 22:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	Release 1.10
+	Tested linux releases: 1.2.13, 1.3.45, 1.3.71, 1.3.90, 1.3.100
+	                       1.99.6, 1.99.7
+	Switch between Drew's driver and Bsd driver tested for 1.99.7.
+	Both driver was made as modules.
+
+Sat May 25 16:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	Some weird problems happen with multi-lun configurations and HDs.
+	SDTR seems to be sent with TEST UNIT READY of lun 1.
+	Tagged Queue cannot be enabled. It seems that inqdata are 
+	filled with garbage probably due to some INQUIRY command to
+	lun 1.
+	I have fixed the problem as follow:
+	- negotiation are initiated only with a command to lun 0.
+	- inquiry data are store only for lun 0.
+
+Wed May 22 22:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c, ncr53c8xx.h
+	Have prepared the patch that allow to install the driver in the 
+	kernel tree, without moving Drew's one.
+	Seems to work. However, I have to check that nothing has been 
+	broken for 1.2.13 and 1.3.45 to 1.3.100.
+
+Sun May 4 22:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.h
+	Adapt the source to some modifications of the linux tree of 1.3.98.
+	(include/linux/scsicam.h moved to include/scsi/scsicam.h)
+
+Thu Apr 25 21:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.h, ncr53c8xx.c
+	Release 1.9
+	Prepare conditionnal compilations for the future Linux version(s).
+	Assume that these versions will be nicely compatible with current 
+	one. 
+	1.3.255, 1.4.0 or 2.0.0 ?
+	I suggest 3.0.0 for some obvious reason.
+
+Wed Apr 24 23:15 1996 Gerard Roudier (groudier@club-internet.fr)
+	* Install.ncr53c8xx
+	Add Patch-Current.ncr53c8xx to the distribution.
+	This patch is applied to the scsi Makefile at installation time for
+	Linux release V.P.S (V*1000000000+P*100000000+S > 1300000094).
+	Each time it'll be necessary I will send the patch corresponding to 
+	the current Linux release to the linux-scsi@vger.rutgers.edu.
+
+Sun Apr 21 19:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* README.ncr53c8xx
+	Update Bonnie results of linux-1.3.92 + prepatch read-ahead 1.3.93.
+	Results are so good that I must remove FreeBSD-2.0.5 results from the
+	README file, otherwise I should cause trouble for myself.
+
+Sun Apr 07 21:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.h
+	Define SCSI_NCR_MAX_LUN (8) inconditionaly.
+	Previous releases did not work for multi-lun devices.
+	This definition was wrongly conditionned:
+	(SCSI_CONFIG_MULTI_LUN instead of CONFIG_SCSI_MULTI_LUN).
+	No luck, since I donnot have multi-lun devices and could'nt
+	test it.
+	Some tests under linux-1.3.84 with an experimental patch that
+	try to do asynchronous read-ahead.
+
+Wed Apr 03 23:15 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.h, ncr53c8xx.c
+	Change some wrong "assert (target == cmd->target & 7)" to
+                          "assert (target == (cmd->target & 0xf)".
+	Remove   NCR_TIMEOUT_ALERT from ncr53c8xx.c
+	Add SCSI_NCR_TIMEOUT_ALERT to   ncr53c8xx.h
+
+Sun Mar 24 21:15 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.h
+	During "make dep" of linux-1.2.13, LINUX_VERSION_CODE is undefined.
+	Have to assume 1.2.13 in such situation.
+	Release 1.8
+
+Sun Mar 24 21:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* README.ncr53c8xx
+	Make changes according to the new uninstallation procedure.
+
+Sun Mar 24 20:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* Uninstall.ncr53c8xx
+	Add an uninstallation script to the distribution.
+	This shell script restore the standard driver.
+	Very usefull for people who prefers to use a driver that
+	does not support:
+	- Master parity check
+	- Tagged command queuing
+	- Fast Wide Scsi-2 features (up to 20 MB/sec)
+	and that would be capable to reject a Wide Negotiation that it had
+	previously initiated.
+
+Sat Mar 23 22:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* README.ncr53c8xx
+	Make changes according to the new installation procedure.
+
+Fri Mar 22 23:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* Install.ncr53c8xx
+	Add an installation script to the distribution.
+	3 differents patches are necessary:
+	- linux-1.2.13
+	- linux-1.3.45 to linux-1.3.49
+        - linux-1.3.50 to linux-1.3.77
+
+Wed Mar 13 22:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c, ncr53c8xx.h
+	Add share irq support.
+	This facility appears with linux-1.3.70. It seems that the
+	corresponding code of the kernel was questionnable before 1.3.72.
+	I decide to support this options from linux-1.3.72 and above.
+	(Add define option SCSI_NCR_SHARE_IRQ)
+	Release 1.7
+
+Tue Mar 12 22:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	Download BSD ncr.c 1.67 and apply the correction of negotiations order.
+	Now the Wide and Sync negotiation are done in the proper order.
+	(Problem reported by Johannes Plass).
+	Round up correctly the announced speed in MB/sec.
+
+Tue Mar 05 22:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* README.ncr53c8xx
+	Have to upload release 1.6 for users of linux-1.3.70-71
+
+Mon Mar 04 16:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* README.ncr53c8xx
+	Add some Bonnie results to the README file.
+
+Sun Mar 03 20:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	Make changes for linux-1.3.70 according to the new specification of
+	irq services interface (request_irq(), free_irq()).
+	With 26 letters, "_", and 10 digits we can build about:
+		53x62**9 C names of 10 characters.
+	Why to use SAME function names with DIFFERENT parameters ?
+
+Sat Mar 02 22:30 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	Using SIMPLE QUEUE TAG for all operations is good for performances,
+	but may be bad for assumed timeout values.
+	Under heavy disk load (Bonnie), the drive may start IO process of a 
+	command, then disconnect, then execute lots of other commands 
+	before completing the interrupted command.
+	The standard value of SD_TIMEOUT (6 sec or 7 sec) seems (is) too short.
+	I fix the problem by forcing an ORDERED QUEUE TAG for the next  
+	command when I found some "old" pending command.
+	"Old" means that they might be timeouted in a few seconds.
+	Add NCR_TIMEOUT_ALERT and set it to 3 seconds.
+
+Fri Mar 01 22:30 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.h, ncr53c8xx.c
+	Add define SCSI_NCR_SEGMENT_SIZE and set it by default to 512.
+	If undefined, the driver use the scatter list given by the upper 
+	scsi driver, else it tries to split segments into shorter one 
+	according to the value of SCSI_NCR_SEGMENT_SIZE.
+
+Tue Feb 27 21:30 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.h
+	Set sg_tablesize to 127 = SCSI_NCR_MAX_SCATTER-1.
+	(was 64 = SCSI_NCR_MAX_SCATTER/2).
+	May increase the speed (about 20%) for linear read/write operations.
+	Bonnie results may be better, but I prefered the previous
+	value.
+
+Tue Feb 27 21:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr54c8xx.c, ncr53c8xx.h
+	Tagged command queueing seems to affect linux-1.3.XY kernels.
+	I decide to disable tagged queue by default and to provide a command
+	tool to enable it per device after boot-up.
+	Add scsitag.c to the distribution.
+	Usage: scsitag device
+	Examples: scsitag /dev/sda
+	          scsitag /dev/sdb
+
+Sun Feb 25 14:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c, ncr53c8xx.h
+	Add INQ7_Default definition and set the target capabilities to this
+	value by default.
+	Add some code to reject a synchronous negotiation request from a target
+	that is defined as not capable of Sync in the table of capabilities.
+	
+Sat Feb 24 23:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	Add some code to fill some write-only host instance fields:
+	- base
+	- io_port
+	- n_io_port
+	- dma_channel
+	This fields may be used with some "standard" drivers that do not 
+	process correctly the release function.
+
+Fri Feb 23 23:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	I receive a mail from Jason Duerstock.
+	A new bug in ncrBsd2Linux which is probably outside the driver code
+	and inside Linux kernel code.
+	The kernel memory is quite corrupted and we cannot get any informations
+	by looking into the messages about the crash. However Linus see a bug in
+	ncrBsd2Linux because it is a "non standard" driver.
+	I think too that ncrBsd2Linux is not a standard driver of Linux kernel,
+	because it has no bugs enough to become standard for Linux.
+	Drew's driver is quite standard.
+
+Wed Feb 21 23:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c, ncr53c8xx.h
+	I incorporate the differences between FreeBSD ncr.c revision 1.62 and
+	revision 1.64.
+	- Some cosmetic changes.
+	- Use M_SIMPLE_TAG by default (even for write operations).
+	  I seems to me that SIMPLE TAG is safe only if the flag "queue
+	  algorithm modifier" is set to zero.
+	  I will ask some questions to Stefan Esser about this.
+	Add option SCSI_NCR_ALWAYS_SIMPLE_TAG in ncr53c8xx.h.
+
+Fri Feb 16 23:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	I have found the bug. It is a recursion in __get_free_pages().
+	I will send a mail to Linus about this.
+
+Sat Feb 10 20:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	I am sure that the kernel stack overflow is due to a severe bug in
+	the Linux kernel.
+	I decide to try to find the bug by myself.
+
+Fri Feb 09 20:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c, ncr53c8xx.h
+	Limit commands per lun to 2 for linux-1.3.XY.
+	The patch-1.3.60 does not correct the kernel stack overflow problem.
+	I decide to make some tests with Drew's driver and Bsd2Linux with same 
+	working conditions (3 commands per lun, FAST SCSI, no command queueing).
+	I get the stack overflow problem with the 2 drivers at the same 
+	frequency.
+	With only 2 commands per lun, I dont have the problem with any driver.
+	It seems that the madness of recursion and the recent introduction of
+	the silly generic read function have broken performance and reliability 
+	of scsi drivers.
+
+Thu Feb 08 23:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c, ncr_attach()
+	Release memory mapped region and io port if initialisation
+	does not succeed.
+
+Thu Feb 08 22:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c, ncr53c8xx.c
+	Try to spare some CPU time in queue_command() function and interrupt
+	handler:
+	Add SCSI_NCR_PARANOIA define option in ncr53c8xx.h.
+	Add SCSI_NCR_PROFILE  define option in ncr53c8xx.h.
+	Avoid useless code and function calls.
+
+Tue Feb 06 21:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c, ncr53c8xx.h, ncr_timeout()
+	Add SCSI_NCR_BROKEN_INTR define option in ncr53c8xx.h.
+	If this option is set, the timeout handler polls the interrupt status
+	register every tick (10 ms). So, boards with broken interrupt can work. 
+
+Mon Feb 05 21:30 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	Print the correct speed, for devices with successfull wide negotiation.
+	For same period, such devices are two times faster then narrow ones.
+
+Mon Feb 05 21:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.h, ncr53c8xx.c, ncr_attach()
+	Add define SCSI_NCR_SETTLE_TIME in header file and set it by default
+	to 2 seconds.
+
+Sat Jan 27 14:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	Upload release 1.3
+
+Wed Jan 24 24:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	Update from ncr Bsd 1.60 (Stefan Esser):
+	The handshake timeout is disabled, since
+	a few devices will delay ACK for more than a 
+	second: Scanner, CDROM writer and a few old hard 
+	disk drives.
+
+Wed Jan 24 22:30 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	Set the selection timeout to 0.4 sec, since 0.25 sec
+	is recommended for scsi-1 devices.
+	Note that the Bsd ncr driver sets this timeout to 0.1 sec
+	and the linux standard ncr driver sets it to 0.8 sec.
+
+Wed Jan 24 22:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	Add a 5 seconds delay after chip initialization,
+	waiting for scsi devices to settle their stomach,
+	as FreeBSD generic scsi driver does.
+
+Tue Jan 23 23:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	Set burst length value according to chip type.
+	The original Bsd ncr driver sets burst length to 16 for
+	all chip types.
+
+Tue Jan 16 23:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c, ncr53c8xx.h
+	Add comments to linux specific glue code.
+
+Mon Jan 15 22:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	io mapped versus memory mapped.
+	* ncr53c8xx.c
+	Add some code to dynamicaly switch to io mapped if memory mapped
+	does not work.
+	No more need to reconfigure, compile and link the kernel if
+	memory mapped is not possible.
+
+Sun Jan 14 18:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	Patch sent to ncr mailing list by Jason Duerstock
+	<jduersto@kendall.mdcc.edu>
+	I have omitted to provide the proc_dir_entry to the middle
+	scsi driver.
+	* ncr53c8xxx.c
+	Add the declaration of the ncr53c8xx proc_dir_entry and return
+	the pointer to middle scsi driver.
+
+Sat Jan 13 01:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	ncrBsd2Linux 1.1 is ready.
+	Upload to sunsite immediatly.
+
+Fri Jan 12 23:45 1996 Gerard Roudier (groudier@club-internet.fr)
+	It seems that scsi-2 devices too may cause problems because they
+	have flawes in the firmware.
+	* ncr53c8xx.h
+	I add a table of capabilities per target.
+	This table contains one byte per target. The value of this byte
+	is anded with byte 7 of INQUIRY data.
+	Edit ncr53c8xx.h and read the corresponding comments for more
+	details.
+
+Wed Jan 10 22:35 1996 Gerard Roudier (groudier@club-internet.fr)
+	I have some time to read the scsi-1 specifications.
+	Some very old scsi devices may cause problems with the ncr Bsd driver
+	for the following raisons:
+	    The Synchronous Negotiation protocol was optional.
+	    The standardized INQUIRY data does not include the byte 7 of
+	    the scsi-2 specifications which contains the capabilities of
+	    the device.
+	I think that negotiation with such devices are very questionnable.
+	* ncr53c8xx.c
+	ncrBsd2Linux 1.1 does not negotiate with scsi-1 devices.
+
+Sat Jan 06 21:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c function ncr_attach()
+	Disable chip interrupt before soft reset in attach procedure.
+	When loadlin is used to boot the system, the state of the NCR chip
+	is unpredicable. This modification avoid unexpected interrupts.
+	
+Thu Jan 04 23:45 1996 Gerard Roudier (groudier@club-internet.fr)
+	ncrBsd2Linux 1.0 is ready.
+	Upload to sunsite immediatly.
+
+Tue Jan 02 23:00 1996 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	Add a waiting list for Scsi Commands than can be inserted
+	into the start queue immediatly.
+	When a command complete, the waiting commands are requeued by calling
+	the queuecommand() function.
+
+Sun Dec 31 23:59 1995 Gerard Roudier (groudier@club-internet.fr)
+	* ncr53c8xx.c
+	Use kmalloc()/kfree() for internal data structures allocation to
+	avoid scsi memory pool shortage.
+
+Sat Dec 30 23:00 1995 Gerard Roudier (groudier@club-internet.fr)
+	ncrBsd2Linux can now use memory mapped IO.
+	Works fine.
+	* ncr53c8xx.c
+	    Call vremap() from ncr_attach() to map the physical page which
+	    contains the memory IO window.
+	    Call vfree() from ncr_detach() (release module).
+
+Fri Dec 29 23:45 1995 Gerard Roudier (groudier@club-internet.fr)
+	ncrBsd2Linux can now be configured as a module.
+	Works fine.
+	* ncr53c8xx.c: add new functions ncr53c8xx_release() and ncr_detach()
+	Add the code to (per host):
+	    Stop the timer.
+	    Stop the chip.
+	    Free allocated memory.
+
+Fri Dec 29 23:00 1995 Gerard Roudier (groudier@club-internet.fr)
+	Problem: detection routine returns 0 and can detect only one host.
+	* ncr53c8xx.c function ncr_attach()
+	ncr_attach() now returns 0 on success and -1 on error.
+	ncr53c8xx_detect() returns the number of detected hosts.
+
+Thu Dec 28 22:00 1995 Gerard Roudier (groudier@club-internet.fr)
+	I must upload the new version which corrects the severe problem with
+	WRITE_10 command.
+	Release 0.5
+	Known or probable problems with this ncr driver release:
+	--------------------------------------------------------
+	    Same as the previous release.
+
+Wed Dec 27 23:00 1995 Gerard Roudier (groudier@club-internet.fr)
+	Problem:
+	    System CRASH or scsi ERROR "extra data disgarded" on WRITE(10)
+	    command. 
+	* ncr53c8xx.c function guess_xfer_direction()
+	I add the WRITE(10) (0x2A) into the list of Data Out scsi commands.
+	It was a big mistake.
+	This BUG was introduced in the release 0.3 and is obvious present in
+	the release 0.4.
+
+Wed Dec 27 22:00 1995 Gerard Roudier (groudier@club-internet.fr)
+	Problem:
+	    When I was testing tagged command queueing and disconnections
+	    with one hard disk at a time (IBM S12), the script process hung 
+	    every 5 minutes with a non empty stall queue.
+	* ncr53c8xx.c function ncr_exception()
+	I replace "OUTB (nc_istat, INTF)" by
+	          "OUTB (nc_istat, (istat & SIGP) | INTF)".
+	This statement cleared the INTF condition, but cleared the SIGP flag too.
+	(This bug is in the original FreeBSD ncr driver).
+
+Mon Dec 25 22:00 1995 Gerard Roudier (groudier@club-internet.fr)
+	Release 0.4
+	Known or probable problems with this ncr driver release:
+	--------------------------------------------------------
+	  Hardware (or software) conflicts with some ethernet cards.
+	      See release 0.2 above.
+	  Crash with Intel saturn chipset with write-back cache enabled.
+	      The SCSI SCRIPT access the internal registers of
+	      the NCR chip by memory addressing.
+              Ensure that the memory area of the NCR chip is not cacheable.
+	      Use scanpci to get the base memory address of the ncr chip.
+	      The 128 bytes following this address must not be cached.
+
+Sat Dec 23 22:00 1995 Gerard Roudier (groudier@club-internet.fr)
+	Problem:
+		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.
+		If we wanted to avoid unexpected phase changes at all
+		we had to use a break point every 512 bytes.
+		Of course the number of scatter/gather blocks is
+		limited.
+	* ncr53c8xx.c function ncr_scatter()
+	This function has been rewritten according to the above comments.
+	The Linux scatter list is scanned, and blocks are broken as possible
+	into 512 bytes chunks.
+
+Wed Dec 22 22:00 1995 Gerard Roudier (groudier@club-internet.fr)
+	Problem: ensure that there are enough allocated Command Control Blocks
+	         for each unit to enqueue commands according to cmd_per_lun.
+	* ncr53c8xx.c function ncr_allocate_ccb()
+	Allocate all required ccb(s) instead of one at a time.
+
+Mon Dec 18 23:00 1995 Gerard Roudier (groudier@club-internet.fr)
+	Problem: A copy of the system time is used to compute timeouts.
+	         When the system time is changed , we can get spurious timeouts
+	         if scsi commands are pending.
+	* ncr53c8xx.c function ncr_timeout()
+	In FreeBSD the kernel time (volatile struct timeval time) is not
+	affected by settimeofday() or other change time functions.
+	For Linux, I replace "time" by "xtime". But "xtime" is the system time,
+	and is affected by change time functions.
+	If we detect a change <=-1s or >1s we assume system time has been changed.
+	For all active ccb(s), we recompute tlimit.
+	We set heartbeat to thistime to prevent spurious chip reset.
+
+Sun Dec 17 23:00 1995 Gerard Roudier (groudier@club-internet.fr)
+	Release 0.3.
+
+Sun Dec 17 11:00 1995 Gerard Roudier (groudier@club-internet.fr)
+
+	Problem: Linux middle-level scsi driver does not provide the
+	direction of transfert in scsi command parameters.
+	FreeBSD ncr driver need this information to patch the SCSI script
+	for SAVE DATA POINTER and to check actual data transfer direction.
+	* ncr53c8xx.c
+	I add the function guess_xfer_direction(int opcode) which try to
+	guess the transfer direction.
+ 	Unfortunately my documentation about SCSI-II standard is very old.
+	It does not contain PHOTO-CD command specifications.
+	I assume input transfer direction, for unknown command. (not perfect)
+
+Wed Dec 15 23:00 1995 Gerard Roudier (groudier@club-internet.fr)
+
+	It's time to schedule the release 0.2
+	Known or probable problems with this ncr driver release:
+	--------------------------------------------------------
+	  Scsi tapes do not work.
+	  scsi-config-1.5 does not work too.
+	  Hardware (or software) conflicts with some ethernet cards.
+		The linux native ncr53c810 scsi driver does'not use memory
+		mapped IO at all.
+		The BSD driver can use memory mapped IO.
+		Under Linux, i seems to be difficult (or impossible) to map
+		a PCI memory area. So I decide to use normal IO in the code of
+		the ported driver.
+		However, the SCSI SCRIPT access the internal registers of
+		the NCR chip by memory addressing.
+		EThernet cards use a memory area to communicate with the system.
+		I think that this memory area conflicts with the memory area
+		used by the NCR chip.
+		The configuration diskette of your ethernet card can help you
+		to fix the problem (try sofware configurations).
+
+Wed Dec 15 22:00 1995 Gerard Roudier (groudier@club-internet.fr)
+
+	Problem: detection of CD change did not work.
+	* ncr53c8xx.c
+	Signal a CHECK_CONDITION (S_CHECK_COND) to the middle-level
+	scsi drivers when the scsi completion status = S_SENSE|S_GOOD.
+
+	Problem: System hang with status <4/82> after mounting the root
+	         partition. System disk is a QUANTUM EMPIRE 1080 S.
+	Submitted by rwilhelm@Physik.TU-Muenchen.DE (Robert Wilhelm)
+	Thu, 14 Dec 1995 10:18:43 +0100 (MET)
+	* ncr53c8xx.c
+	Signal a CHECK_CONDITION (S_CHECK_COND) to the middle-level
+	scsi drivers when the scsi completion status = S_SENSE|S_CHECK_COND.
+	(HS_COMPLETE=4, S_SENSE|S_CHECK_COND=x82).
+	I can't test this fix. I think that it should work.
+
+Thu Dec 14 22:00 1995 Gerard Roudier (groudier@club-internet.fr)
+
+	Problem	submitted by Bill Dyess <Bill@Dyess.com> Tue 12 Dec 1995
+	Only one lun detected on a Pioneer DRM-602X 6-disk CD-ROM changer.
+	* ncr53c8xx.h, ncr53c8xx.c
+	Define NCR_SCSI_MAX_LUN to 8 if the Linux configuration flag
+	SCSI_CONFIG_MULTI_LUN is set.
+	My CD device has only one lun. I can't test multi-lun device,
+	but I think that it should work.
+
+	* ncr53c8xx.c
+	Write the ncr_abort_command() and ncr_reset_command() functions.
+	I intend to test these functions next week.
+
+Sun Dec 10 22:00 1995 Gerard Roudier (groudier@club-internet.fr)
+	* Release 0.1
+	Works fine with hard disks under Linux 1.2.13 and Linux 1.3.45.
diff -u --recursive --new-file v2.0.2/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.0.2/linux/drivers/scsi/Config.in	Wed Jul  3 22:05:10 1996
+++ linux/drivers/scsi/Config.in	Sat Jul  6 12:06:37 1996
@@ -44,6 +44,24 @@
     bool '   allow DISCONNECT' CONFIG_SCSI_NCR53C7xx_DISCONNECT
   fi
 fi
+if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_NCR53C7xx" != "y" ]; then
+  if [ "$CONFIG_SCSI" != "n" -a "$CONFIG_SCSI_NCR53C7xx" = "m" ]; then
+    dep_tristate 'NCR53C8XX SCSI support'  CONFIG_SCSI_NCR53C8XX m
+  else
+    dep_tristate 'NCR53C8XX SCSI support'  CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
+  fi
+  if [ "$CONFIG_SCSI_NCR53C8XX" != "n" ]; then
+    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
+  fi
+fi
 dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI
 dep_tristate 'PAS16 SCSI support' CONFIG_SCSI_PAS16 $CONFIG_SCSI
 dep_tristate 'Qlogic FAS SCSI support' CONFIG_SCSI_QLOGIC_FAS $CONFIG_SCSI
diff -u --recursive --new-file v2.0.2/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v2.0.2/linux/drivers/scsi/Makefile	Sun Jun  9 13:28:46 1996
+++ linux/drivers/scsi/Makefile	Sat Jul  6 12:06:37 1996
@@ -263,6 +263,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_SCSI_NCR53C8XX),y)
+L_OBJS += ncr53c8xx.o 
+else
+  ifeq ($(CONFIG_SCSI_NCR53C8XX),m)
+  M_OBJS += ncr53c8xx.o
+  endif
+endif
+
 ifeq ($(CONFIG_SCSI_PAS16),y)
 L_OBJS += pas16.o
 else
@@ -361,6 +369,9 @@
 	mv script.h 53c8xx_d.h
 	mv scriptu.h 53c8xx_u.h
 	rm fake.c
+
+ncr53c8xx.o : ncr53c8xx.c
+	$(CC) $(CFLAGS) -c ncr53c8xx.c
 
 scsi_mod.o: $(MX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \
 		scsicam.o scsi_proc.o
diff -u --recursive --new-file v2.0.2/linux/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx
--- v2.0.2/linux/drivers/scsi/README.ncr53c8xx	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/README.ncr53c8xx	Sat Jul  6 12:06:37 1996
@@ -0,0 +1,560 @@
+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
+===============================================================================
+
+1.  Introduction
+2.  Supported chips and SCSI features
+3.  Summary of other supported features
+4.  Memory mapped IO versus normal IO
+5.  Tagged command queueing
+6.  Parity checking
+7.  Profiling information
+8.  Control commands
+      8.1  Set minimum synchronous period
+      8.2  Set wide size
+      8.3  Set maximum number of concurrent tagged commands
+      8.4  Set order type for tagged command
+      8.5  Set debug mode
+      8.6  Clear profile counters
+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
+
+===============================================================================
+
+1. Introduction
+
+This driver has been ported from FreeBSD to Linux and is currently 
+maintained by:
+          Gerard Roudier              <groudier@club-internet.fr>
+
+The original driver has been written for 386bsd and FreeBSD by
+          Wolfgang Stanglmeier        <wolf@cologne.de>
+          Stefan Esser                <se@mi.Uni-Koeln.de>
+
+You can find technical informations about the NCR 8xx family in the PCI-HOWTO 
+written by Michael Will and in the SCSI-HOWTO written by Drew Eckhardt.
+
+Informations 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.
+
+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.
+
+I am not a native speaker of English and there is probably lots of 
+mistakes in this README file. Any help will be welcome.
+
+
+2. Supported chips and SCSI features
+
+The following features are supported for all chips:
+
+	Synchronous negotiation
+	Disconnection
+	Tagged command queuing
+	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:
+
+       On board                        Supported by    Tested with
+Chip   SDMS BIOS   Wide   Ultra Scsi   the driver      the driver
+----   ---------   ----   ----------   ------------    -----------
+810        N         N        N            Y             Y
+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.
+
+
+3. Summary of other supported features.
+
+        Module:                allow to load the driver
+        Memory mapped IO:      increase performances
+        Profiling information: read operations from the proc scsi file system
+        Control commands:      write operations to the proc scsi file system
+        Debugging information: written to syslog (expert only)
+	Scatter / gather
+	Shared interrupt
+
+
+4. Memory mapped IO versus normal IO
+
+Memory mapped IO have less latency than normal IO.
+Since linux-1.3.x, memory mapped IO is used rather than normal IO.
+Memory mapped IO seems to works fine on most hardware configuration, but some 
+bad designed motherboards may break this feature.
+
+During initialisation 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 io does not work properly and the 
+driver has not detected the problem.
+
+The configuration option CONFIG_SCSI_NCR53C8XX_IOMAPPED allow to force the 
+driver to use normal io in all cases.
+
+
+5. Tagged command queueing
+
+Some scsi devices donnot support properly tagged command queuing.
+A safe configuration can be 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 support properly tagged command queuing,
+you can enable it by default with the CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE 
+configuration option.
+
+
+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:
+
+   CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK  (disable scsi parity checking)
+   CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK (disable master parity checking)
+
+
+7. Profiling information
+
+Profiling information are 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 the device is:
+          /proc/scsi/ncr53c8xx/0
+
+However, if the driver has been made as module, the number of the host is 
+incremented each time the driver is loaded.
+
+In order to display profiling informations, just enter:
+         cat /proc/scsi/ncr53c8xx/0
+and you will get something like the following text:
+
+-------------------------------------------------------
+General informations:
+  Chip NCR53C810, device id 0x1, revision id 0x2
+  IO port address 0x6000, IRQ number 10
+  Using memory mapped IO at virtual address 0x282c000
+Profiling informations:
+  num_trans    = 18014
+  num_kbytes   = 671314
+  num_disc     = 25763
+  num_break    = 1673
+  num_int      = 1685
+  num_fly      = 18038
+  ms_setup     = 4940
+  ms_data      = 369940
+  ms_disc      = 183090
+  ms_post      = 1320
+-------------------------------------------------------
+
+General informations are easy to understand. The device id and the 
+revision id identify the scsi chip as follow:
+
+Chip    Device id     Revision Id
+----    ---------     -----------
+810       0x1            <  0x10
+810A      0x1            >= 0x10
+815       0x4
+825       0x3            <  0x10
+860       0x6
+825A      0x3            >= 0x10
+875       0xf
+
+The profiling informations are updated upon completion of scsi commands.
+The data structure is allocated and zeroed when the host adapter is 
+attached. So, if the driver is a module you can reset the profiling data 
+by unloading and reloading the driver.
+
+The following counters are available:
+("num" prefix means "number of", "ms" means milli-seconds)
+
+num_trans
+	Number of completed commands
+	Example above: 18014 completed commands
+
+num_kbytes
+	Number of kbytes transferred
+	Example above: 671 MB transferred
+
+num_disc
+	Number of scsi disconnections
+	Example above: 25763 scsi disconnections
+
+num_break
+	number of script interruptions (phase mismatch)
+	Example above: 1673 script interruptions
+
+num_int
+	Number of interrupts other than "on the fly"
+	Example above: 1685 interruptions not "on the fly"
+
+num_fly
+	Number of interrupts "on the fly"
+	Example above: 18038 interruptions "on the fly"
+
+ms_setup
+	Elapsed time for scsi commands setups
+	Example above: 4.94 seconds
+
+ms_data
+	Elapsed time for data transfers
+	Example above: 369.94 seconds spent for data transfer
+
+ms_disc
+	Elapsed time for scsi disconnections
+	Example above: 183.09 seconds spent disconnected
+
+ms_post
+	Elapsed time for command post processing
+	(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.
+
+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. 
+It 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 performances, and it seems that it 
+is 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)
+
+
+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:
+
+      echo "<verb> <parameters>" >/proc/scsi/ncr53c8xx/0
+      (assumes controller number is 0)
+
+Available commands:
+
+8.1 Set minimum synchronous period
+
+    setsync <target> <period>
+
+    target:    target number
+    period:    minimum synchronous period in nano-seconds.
+               Maximum speed = 1000/(4*period) MB/second
+
+    Specify a period of 255, to force asynchronous transfer mode.
+
+8.2 Set wide size
+
+    setwide <target> <size>
+
+    target:    target number
+    size:      0=8 bits, 1=16bits
+
+8.3 Set maximum number of concurrent tagged commands
+ 
+    settags <target> <tags>
+
+    target:    target number
+    tags:      number of concurrent tagged commands
+               must not be greater than SCSI_NCR_MAX_TAGS (default: 4)
+
+8.4 Set order type for tagged command
+
+    setorder <order>
+
+    order:     3 possible values:
+               simple: use SIMPLE TAG for all operations (read and write)
+               ordered: use ORDERED TAG for all operations
+               default: use default tag type,
+                        SIMPLE  TAG for read  operations
+                        ORDERED TAG for write operations
+
+
+8.5 Set debug mode
+
+    setdebug <list of debug flags>
+
+    Available debug flags:
+        alloc:   print infos about memory allocations (ccb, lcb)
+        queue:   print infos about insertions into the command start queue
+        result:  print sense data on CHECK CONDITION status
+        scatter: print infos about the scatter process
+        scripts: print infos about the script binding process
+	tiny:    print minimal debugging informations
+	timing:  print timing informations of the ncr chip.
+	nego:    print informations about scsi negotiations
+        phase:   printf informations on script interruptions
+
+
+8.5 Clear profile counters
+
+    clearprof
+
+    The profile counters are automatically cleared when the amount of data 
+    transfered reach 1000 GB in order to avoid overflow.
+    The "clearprof" command allow to clear these counters at any time.
+
+
+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.
+
+CONFIG_SCSI_NCR53C8XX_IOMAPPED       (default answer: n)
+    Answer "y" if you suspect your mother board to not allow memory mapped IO.
+    May slow down a little performances.
+
+CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE    (default answer: n)
+    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 allow to force asynchronous transfer mode for all scsi devices. 
+ 
+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 
+    response and however support it properly (TAMARACK scanners for example).
+
+CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT   (default and only reasonnable answer: n)
+    If you suspect a device of yours to not support properly disconnections,
+    you can answer "y". Then, all scsi devices will never disconnect the bus 
+    even while 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.
+
+SCSI_NCR_IOMAPPED		(default: not defined)
+	If defined, normal IO is forced.
+
+SCSI_NCR_SHARE_IRQ		(default: defined)
+	If defined, request shared irq.
+	
+SCSI_NCR_MAX_TAGS		(default: 4)
+	Maximum number of simultaneous tagged commands to a device.
+	Can be changed by "settags <target> <maxtags>"
+
+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_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_DISABLE_PARITY_CHECK	(default: not defined)
+	If defined, scsi parity checking is disabled.
+
+SCSI_NCR_PROFILE		(default: defined)
+	If defined, profile informations are gathered
+
+SCSI_NCR_MAX_SCATTER		(default: 128)
+	Scatter list size of the driver ccb.
+
+SCSI_NCR_SEGMENT_SIZE		(default: 512)
+	If defined, the driver 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 target per host.
+
+SCSI_NCR_MAX_HOST		(default: 2)
+	Max number of host controllers.
+
+SCSI_NCR_SETTLE_TIME		(default: 2)
+	Number of seconds the driver wait after reset.
+
+SCSI_NCR_TIMEOUT_ALERT		(default: 3)
+	If a pending command will time out after this amount of seconds,
+	an ordered tag is used for the next command.
+	Avoid timeouts for unordered tagged commands.
+
+SCSI_NCR_CAN_QUEUE		(default: 7*SCSI_NCR_MAX_TAGS)
+	Max number of commands that can be queued to a host.
+
+SCSI_NCR_CMD_PER_LUN		(default: SCSI_NCR_MAX_TAGS)
+	Max number of commands queued to a host for a device.
+
+SCSI_NCR_SG_TABLESIZE		(default: SCSI_NCR_MAX_SCATTER-1)
+	Max size of the Linux scatter/gather list.
+
+SCSI_NCR_MAX_LUN	(default: 8)
+	Max number of luns per target
+
+
+11. Provided files
+
+Driver and common files:
+
+	README.ncr53c8xx	: this file
+	ChangeLog.ncr53c8xx	: change log
+	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
+
+	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
+
+Prior to installing the driver, you must untar the distribution, as follow:
+
+	mkdir ncrB2L
+	cd ncrB2L
+	tar zxvf ncrBsd2Linux-1.12a-src.tar.gz
+
+
+12. Installation procedure for Linux version 1
+
+This install script only supports linux-1.2.13 and linux-1.3.45 to 1.3.100.
+
+This procedure just move 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
+
+	If your linux directory is at the standard location
+	"/usr/src/linux", just enter:
+		Install.ncr53c8xx
+
+	Else enter:
+		Install.ncr53c8xx <your_linux_directory>
+
+	Make the kernel:
+		Change to linux source directory
+		Configure with 53c7,8xx support (Y or m)  for Install.ncr53c8xx
+		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 ignore 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 add 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 the both drivers as module 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
+
+	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
+
+Profile 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 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
+
+15.1 Tagged commands with Iomega Jaz device
+
+I never tried such devices, 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 problems that may appear are timeouts. The only way to avoid timeouts 
+seems to edit linux/drivers/scsi/sd.c and to increase the current timeout 
+values.
+
+===============================================================================
+End of NCR53C8XX driver README file
diff -u --recursive --new-file v2.0.2/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v2.0.2/linux/drivers/scsi/hosts.c	Wed Jun  5 10:41:28 1996
+++ linux/drivers/scsi/hosts.c	Sat Jul  6 12:06:37 1996
@@ -133,6 +133,10 @@
 #include "53c7,8xx.h"
 #endif
 
+#ifdef CONFIG_SCSI_NCR53C8XX
+#include "ncr53c8xx.h"
+#endif
+
 #ifdef CONFIG_SCSI_ULTRASTOR
 #include "ultrastor.h"
 #endif
@@ -271,6 +275,9 @@
 #endif
 #ifdef CONFIG_SCSI_NCR53C7xx
     NCR53c7xx,
+#endif
+#ifdef CONFIG_SCSI_NCR53C8XX
+    NCR53C8XX,
 #endif
 #ifdef CONFIG_SCSI_EATA_DMA
     EATA_DMA,
diff -u --recursive --new-file v2.0.2/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.0.2/linux/drivers/scsi/ncr53c8xx.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/ncr53c8xx.c	Sat Jul  6 12:06:37 1996
@@ -0,0 +1,8183 @@
+/******************************************************************************
+**  Device driver for the PCI-SCSI NCR538XX controller family.
+**
+**  Copyright (C) 1994  Wolfgang Stanglmeier
+**
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**-----------------------------------------------------------------------------
+**
+**  This driver has been ported to Linux from the FreeBSD NCR53C8XX driver
+**  and is currently maintained by
+**
+**          Gerard Roudier              <groudier@club-internet.fr>
+**
+**  Being given that this driver originates from the FreeBSD version, and
+**  in order to keep synergy on both, any suggested enhancements and corrections
+**  received on Linux are automatically a potential candidate for the FreeBSD 
+**  version.
+**
+**  The original driver has been written for 386bsd and FreeBSD by
+**          Wolfgang Stanglmeier        <wolf@cologne.de>
+**          Stefan Esser                <se@mi.Uni-Koeln.de>
+**
+**  And has been ported to NetBSD by
+**          Charles M. Hannum           <mycroft@gnu.ai.mit.edu>
+**
+*******************************************************************************
+*/
+
+/*
+**	23 June 1996, version 1.12
+**
+**	Supported SCSI-II features:
+**	    Synchronous negotiation
+**	    Wide negotiation        (depends on the NCR Chip)
+**	    Enable disconnection
+**	    Tagged command queuing
+**	    Parity checking
+**	    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)
+**
+**	Other features:
+**		Memory mapped IO (linux-1.3.X 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
+
+/*==========================================================
+**
+**      Include files
+**
+**==========================================================
+*/
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
+#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/bios32.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+#include <linux/stat.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
+#include "linux/blk.h"
+#else
+#include "../block/blk.h"
+#endif
+
+#include "scsi.h"
+#include "hosts.h"
+#include "constants.h"
+#include "sd.h"
+
+#include <linux/types.h>
+
+/*
+**	Define the BSD style u_int32 type
+*/
+typedef u32 u_int32;
+
+#include "ncr53c8xx.h"
+
+/*==========================================================
+**
+**	Configuration and Debugging
+**
+**==========================================================
+*/
+
+/*
+**	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.
+*/
+
+#ifndef SCSI_NCR_MYADDR
+#define SCSI_NCR_MYADDR      (7)
+#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.
+*/
+
+#ifndef SCSI_NCR_MAX_TAGS
+#define SCSI_NCR_MAX_TAGS    (4)
+#endif
+
+/*==========================================================
+**
+**      Configuration and Debugging
+**
+**==========================================================
+*/
+
+/*
+**    Number of targets supported by the driver.
+**    n permits target numbers 0..n-1.
+**    Default is 7, meaning targets #0..#6.
+**    #7 .. is myself.
+*/
+
+#ifdef SCSI_NCR_MAX_TARGET
+#define MAX_TARGET  (SCSI_NCR_MAX_TARGET)
+#else
+#define MAX_TARGET  (16)
+#endif
+
+/*
+**    Number of logic units supported by the driver.
+**    n enables logic unit numbers 0..n-1.
+**    The common SCSI devices require only
+**    one lun, so take 1 as the default.
+*/
+
+#ifdef SCSI_NCR_MAX_LUN
+#define MAX_LUN    SCSI_NCR_MAX_LUN
+#else
+#define MAX_LUN    (1)
+#endif
+ 
+
+/*
+**    The maximum number of jobs scheduled for starting.
+**    There should be one slot per target, and one slot
+**    for each tag of each target in use.
+**    The calculation below is actually quite silly ...
+*/
+
+#ifdef SCSI_NCR_CAN_QUEUE
+#define MAX_START   (SCSI_NCR_CAN_QUEUE + 4)
+#else
+#define MAX_START   (MAX_TARGET + 7 * SCSI_NCR_MAX_TAGS)
+#endif
+
+/*
+**    The maximum number of segments a transfer is split into.
+*/
+
+#define MAX_SCATTER (SCSI_NCR_MAX_SCATTER)
+
+/*
+**    The maximum transfer length (should be >= 64k).
+**    MUST NOT be greater than (MAX_SCATTER-1) * NBPG.
+*/
+
+#if 0
+#define MAX_SIZE  ((MAX_SCATTER-1) * (long) NBPG)
+#endif
+
+/*
+**	other
+*/
+
+#define NCR_SNOOP_TIMEOUT (1000000)
+
+#ifdef SCSI_NCR_IOMAPPED
+#define NCR_IOMAPPED
+#endif
+
+/*==========================================================
+**
+**	Defines for Linux.
+**
+**	Linux and Bsd kernel functions are quite different.
+**	These defines allow a minimum change of the original
+**	code.
+**
+**==========================================================
+*/
+
+ /*
+ **	Obvious definitions
+ */
+
+#define printf		printk
+#define u_char		unsigned char
+#define u_short		unsigned short
+#define u_int		unsigned int
+#define u_long		unsigned long
+
+typedef	u_long		vm_offset_t;
+typedef	int		vm_size_t;
+
+#define bcopy(s, d, n)	memcpy((d), (s), (n))
+#define bzero(d, n)	memset((d), 0, (n))
+
+#ifndef offsetof
+#define offsetof(t, m)	((size_t) (&((t *)0)->m))
+#endif
+
+/*
+**	Address translation
+**
+**	On Linux 1.3.X, virt_to_bus() must be used to translate
+**	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.
+**	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().
+*/
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
+#define vtophys(p)	virt_to_bus(p)
+
+/*
+**	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.
+*/
+
+static inline 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;
+	u_long page_remapped	= (u_long) vremap(page_base, page_offs+size);
+
+	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));
+}
+
+#else
+
+/*
+**	Linux 1.2.X assumes that addresses (virtual, physical, bus)
+**	are the same.
+**
+**	I have not found how to do MMIO. It seems that only processes can
+**	map high physical pages to virtual (Xservers can do MMIO).
+*/
+
+#define vtophys(p)	((u_long) (p))
+#endif
+
+static void DELAY(long us)
+{
+	for (;us>1000;us-=1000) udelay(1000);
+	if (us) udelay(us);
+}
+
+/*
+**	Internal data structure allocation.
+**
+**	Linux scsi memory poor pool is adjusted for the need of
+**	middle-level scsi driver.
+**	We allocate our control blocks in the kernel memory pool
+**	to avoid scsi pool shortage.
+**	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.
+**/
+
+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); }
+
+/*
+**	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.
+*/
+
+#define XferNone	0
+#define XferIn		1
+#define XferOut		2
+#define XferBoth	3
+static int guess_xfer_direction(int opcode);
+
+/*
+**	Head of list of NCR boards
+**
+**	Host is retrieved by its irq level.
+*/
+
+static struct Scsi_Host		*first_host	= NULL;
+static Scsi_Host_Template	*the_template	= NULL;	
+
+
+/*
+**	/proc directory entry and proc_info function
+*/
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
+struct proc_dir_entry proc_scsi_ncr53c8xx = {
+    PROC_SCSI_NCR53C8XX, 9, "ncr53c8xx",
+    S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+# ifdef SCSI_NCR_PROC_INFO_SUPPORT
+int ncr53c8xx_proc_info(char *buffer, char **start, off_t offset,
+			int length, int hostno, int func);
+# endif
+#endif
+
+/*
+**	Table of target capabilities.
+**
+**	This bitmap is anded with the byte 7 of inquiry data on completion of
+**	INQUIRY command.
+** 	The driver never see zeroed bits and will ignore the corresponding
+**	capabilities of the target.
+*/
+
+static struct {
+	unsigned char and_map[MAX_TARGET];
+} target_capabilities[SCSI_NCR_MAX_HOST] = { NCR53C8XX_TARGET_CAPABILITIES };
+
+
+/*
+**	Other Linux definitions
+*/
+
+#define ScsiResult(host_code, scsi_code) (((host_code) << 16) + ((scsi_code) & 0x7f))
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
+static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
+#else
+static void ncr53c8xx_intr(int irq, struct pt_regs * regs);
+#endif
+
+static void ncr53c8xx_timeout(unsigned long np);
+
+#define bootverbose 1
+
+/*==========================================================
+**
+**	Debugging tags
+**
+**==========================================================
+*/
+
+#define DEBUG_ALLOC    (0x0001)
+#define DEBUG_PHASE    (0x0002)
+#define DEBUG_POLL     (0x0004)
+#define DEBUG_QUEUE    (0x0008)
+#define DEBUG_RESULT   (0x0010)
+#define DEBUG_SCATTER  (0x0020)
+#define DEBUG_SCRIPT   (0x0040)
+#define DEBUG_TINY     (0x0080)
+#define DEBUG_TIMING   (0x0100)
+#define DEBUG_NEGO     (0x0200)
+#define DEBUG_TAGS     (0x0400)
+#define DEBUG_FREEZE   (0x0800)
+#define DEBUG_RESTART  (0x1000)
+
+/*
+**    Enable/Disable debug messages.
+**    Can be changed at runtime too.
+*/
+
+#ifdef SCSI_NCR_DEBUG
+	#define DEBUG_FLAGS ncr_debug
+#else
+	#define DEBUG_FLAGS	SCSI_NCR_DEBUG_FLAGS
+#endif
+
+
+
+/*==========================================================
+**
+**	assert ()
+**
+**==========================================================
+**
+**	modified copy from 386bsd:/usr/include/sys/assert.h
+**
+**----------------------------------------------------------
+*/
+
+#define	assert(expression) { \
+	if (!(expression)) { \
+		(void)printf(\
+			"assertion \"%s\" failed: file \"%s\", line %d\n", \
+			#expression, \
+			__FILE__, __LINE__); \
+	} \
+}
+
+/*==========================================================
+**
+**	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
+*/
+
+#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))
+
+/*
+**	IO mapped only input / output
+*/
+
+#ifdef NCR_IOMAPPED
+
+#define INB(r)             IOM_INB(r)
+#define INB_OFF(o)         IOM_INB_OFF(o)
+#define INW(r)             IOM_INW(r)
+#define INL(r)             IOM_INL(r)
+#define INL_OFF(r)         IOM_INL_OFF(o)
+
+#define OUTB(r, val)       IOM_OUTB(r, val)
+#define OUTW(r, val)       IOM_OUTW(r, val)
+#define OUTL(r, val)       IOM_OUTL(r, val)
+#define OUTL_OFF(o, val)   IOM_OUTL_OFF(o, val)
+
+/*
+**	IO mapped or MEMORY mapped depending on flag "use_mmio"
+*/
+
+#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))
+
+#endif
+
+/*==========================================================
+**
+**	Command control block states.
+**
+**==========================================================
+*/
+
+#define HS_IDLE		(0)
+#define HS_BUSY		(1)
+#define HS_NEGOTIATE	(2)	/* sync/wide data transfer*/
+#define HS_DISCONNECT	(3)	/* Disconnected by target */
+
+#define HS_COMPLETE	(4)
+#define HS_SEL_TIMEOUT	(5)	/* Selection timeout      */
+#define HS_RESET	(6)	/* SCSI reset	     */
+#define HS_ABORTED	(7)	/* Transfer aborted       */
+#define HS_TIMEOUT	(8)	/* Software timeout       */
+#define HS_FAIL		(9)	/* SCSI or PCI bus errors */
+#define HS_UNEXPECTED	(10)	/* Unexpected disconnect  */
+
+#define HS_DONEMASK	(0xfc)
+
+/*==========================================================
+**
+**	Software Interrupt Codes
+**
+**==========================================================
+*/
+
+#define	SIR_SENSE_RESTART	(1)
+#define	SIR_SENSE_FAILED	(2)
+#define	SIR_STALL_RESTART	(3)
+#define	SIR_STALL_QUEUE		(4)
+#define	SIR_NEGO_SYNC		(5)
+#define	SIR_NEGO_WIDE		(6)
+#define	SIR_NEGO_FAILED		(7)
+#define	SIR_NEGO_PROTO		(8)
+#define	SIR_REJECT_RECEIVED	(9)
+#define	SIR_REJECT_SENT		(10)
+#define	SIR_IGN_RESIDUE		(11)
+#define	SIR_MISSING_SAVE	(12)
+#define	SIR_MAX			(12)
+
+/*==========================================================
+**
+**	Extended error codes.
+**	xerr_status field of struct ccb.
+**
+**==========================================================
+*/
+
+#define	XE_OK		(0)
+#define	XE_EXTRA_DATA	(1)	/* unexpected data phase */
+#define	XE_BAD_PHASE	(2)	/* illegal phase (4/5)   */
+
+/*==========================================================
+**
+**	Negotiation status.
+**	nego_status field	of struct ccb.
+**
+**==========================================================
+*/
+
+#define NS_SYNC		(1)
+#define NS_WIDE		(2)
+
+/*==========================================================
+**
+**	"Special features" of targets.
+**	quirks field		of struct tcb.
+**	actualquirks field	of struct ccb.
+**
+**==========================================================
+*/
+
+#define	QUIRK_AUTOSAVE	(0x01)
+#define	QUIRK_NOMSG	(0x02)
+#define QUIRK_NOSYNC	(0x10)
+#define QUIRK_NOWIDE16	(0x20)
+#define	QUIRK_UPDATE	(0x80)
+
+/*==========================================================
+**
+**	Capability bits in Inquire response byte 7.
+**
+**==========================================================
+*/
+
+#define	INQ7_QUEUE	(0x02)
+#define	INQ7_SYNC	(0x10)
+#define	INQ7_WIDE16	(0x20)
+
+/*==========================================================
+**
+**	Misc.
+**
+**==========================================================
+*/
+
+#define CCB_MAGIC	(0xf2691ad2)
+#define	MAX_TAGS	(16)		/* hard limit */
+
+/*==========================================================
+**
+**	Declaration of structs.
+**
+**==========================================================
+*/
+
+struct tcb;
+struct lcb;
+struct ccb;
+struct ncb;
+struct script;
+
+typedef struct ncb * ncb_p;
+typedef struct tcb * tcb_p;
+typedef struct lcb * lcb_p;
+typedef struct ccb * ccb_p;
+
+struct link {
+	ncrcmd	l_cmd;
+	ncrcmd	l_paddr;
+};
+
+struct	usrcmd {
+	u_long	target;
+	u_long	lun;
+	u_long	data;
+	u_long	cmd;
+};
+
+#define UC_SETSYNC      10
+#define UC_SETTAGS	11
+#define UC_SETDEBUG	12
+#define UC_SETORDER	13
+#define UC_SETWIDE	14
+#define UC_SETFLAG	15
+#define UC_CLEARPROF	16
+
+#define	UF_TRACE	(0x01)
+
+/*---------------------------------------
+**
+**	Timestamps for profiling
+**
+**---------------------------------------
+*/
+
+struct tstamp {
+	u_long start;
+	u_long end;
+	u_long select;
+	u_long command;
+	u_long data;
+	u_long status;
+	u_long disconnect;
+	u_long reselect;
+};
+
+/*
+**	profiling data (per device)
+*/
+
+struct profile {
+	u_long	num_trans;
+	u_long	num_kbytes;
+	u_long	rest_bytes;
+	u_long	num_disc;
+	u_long	num_break;
+	u_long	num_int;
+	u_long	num_fly;
+	u_long	ms_setup;
+	u_long	ms_data;
+	u_long	ms_disc;
+	u_long	ms_post;
+};
+
+/*==========================================================
+**
+**	Declaration of structs:		target control block
+**
+**==========================================================
+*/
+
+struct tcb {
+	/*
+	**	during reselection the ncr jumps to this point
+	**	with SFBR set to the encoded target number
+	**	with bit 7 set.
+	**	if it's not this target, jump to the next.
+	**
+	**	JUMP  IF (SFBR != #target#)
+	**	@(next tcb)
+	*/
+
+	struct link   jump_tcb;
+
+	/*
+	**	load the actual values for the sxfer and the scntl3
+	**	register (sync/wide mode).
+	**
+	**	SCR_COPY (1);
+	**	@(sval field of this tcb)
+	**	@(sxfer register)
+	**	SCR_COPY (1);
+	**	@(wval field of this tcb)
+	**	@(scntl3 register)
+	*/
+
+	ncrcmd	getscr[6];
+
+	/*
+	**	if next message is "identify"
+	**	then load the message to SFBR,
+	**	else load 0 to SFBR.
+	**
+	**	CALL
+	**	<RESEL_LUN>
+	*/
+
+	struct link   call_lun;
+
+	/*
+	**	now look for the right lun.
+	**
+	**	JUMP
+	**	@(first ccb of this lun)
+	*/
+
+	struct link   jump_lcb;
+
+	/*
+	**	pointer to interrupted getcc ccb
+	*/
+
+	ccb_p   hold_cp;
+
+	/*
+	**	statistical data
+	*/
+
+	u_long	transfers;
+	u_long	bytes;
+
+	/*
+	**	user settable limits for sync transfer
+	**	and tagged commands.
+	*/
+
+	u_char	usrsync;
+	u_char	usrtags;
+	u_char	usrwide;
+	u_char	usrflag;
+
+	/*
+	**	negotiation of wide and synch transfer.
+	**	device quirks.
+	*/
+
+/*0*/	u_char	minsync;
+/*1*/	u_char	sval;
+/*2*/	u_short	period;
+/*0*/	u_char	maxoffs;
+
+/*1*/	u_char	quirks;
+
+/*2*/	u_char	widedone;
+/*3*/	u_char	wval;
+	/*
+	**	inquire data
+	*/
+#define MAX_INQUIRE 36
+	u_char	inqdata[MAX_INQUIRE];
+
+	/*
+	**	the lcb's of this tcb
+	*/
+
+	lcb_p   lp[MAX_LUN];
+};
+
+/*==========================================================
+**
+**	Declaration of structs:		lun control block
+**
+**==========================================================
+*/
+
+struct lcb {
+	/*
+	**	during reselection the ncr jumps to this point
+	**	with SFBR set to the "Identify" message.
+	**	if it's not this lun, jump to the next.
+	**
+	**	JUMP  IF (SFBR != #lun#)
+	**	@(next lcb of this target)
+	*/
+
+	struct link	jump_lcb;
+
+	/*
+	**	if next message is "simple tag",
+	**	then load the tag to SFBR,
+	**	else load 0 to SFBR.
+	**
+	**	CALL
+	**	<RESEL_TAG>
+	*/
+
+	struct link	call_tag;
+
+	/*
+	**	now look for the right ccb.
+	**
+	**	JUMP
+	**	@(first ccb of this lun)
+	*/
+
+	struct link	jump_ccb;
+
+	/*
+	**	start of the ccb chain
+	*/
+
+	ccb_p	next_ccb;
+
+	/*
+	**	Control of tagged queueing
+	*/
+
+	u_char		reqccbs;
+	u_char		actccbs;
+	u_char		reqlink;
+	u_char		actlink;
+	u_char		usetags;
+	u_char		lasttag;
+
+	/*-----------------------------------------------
+	**	Flag to force M_ORDERED_TAG on next command
+	**	in order to avoid spurious timeout when
+	**	M_SIMPLE_TAG is used for all operations.
+	**-----------------------------------------------
+	*/
+	u_char	force_ordered_tag;
+#define NCR_TIMEOUT_INCREASE	(5*HZ)
+};
+
+/*==========================================================
+**
+**      Declaration of structs:     COMMAND control block
+**
+**==========================================================
+**
+**	This substructure is copied from the ccb to a
+**	global address after selection (or reselection)
+**	and copied back before disconnect.
+**
+**	These fields are accessible to the script processor.
+**
+**----------------------------------------------------------
+*/
+
+struct head {
+	/*
+	**	Execution of a ccb starts at this point.
+	**	It's a jump to the "SELECT" label
+	**	of the script.
+	**
+	**	After successful selection the script
+	**	processor overwrites it with a jump to
+	**	the IDLE label of the script.
+	*/
+
+	struct link	launch;
+
+	/*
+	**	Saved data pointer.
+	**	Points to the position in the script
+	**	responsible for the actual transfer
+	**	of data.
+	**	It's written after reception of a
+	**	"SAVE_DATA_POINTER" message.
+	**	The goalpointer points after
+	**	the last transfer command.
+	*/
+
+	u_long		savep;
+	u_long		lastp;
+	u_long		goalp;
+
+	/*
+	**	The virtual address of the ccb
+	**	containing this header.
+	*/
+
+	ccb_p	cp;
+
+	/*
+	**	space for some timestamps to gather
+	**	profiling data about devices and this driver.
+	*/
+
+	struct tstamp	stamp;
+
+	/*
+	**	status fields.
+	*/
+
+	u_char		status[8];
+};
+
+/*
+**	The status bytes are used by the host and the script processor.
+**
+**	The first four byte are copied to the scratchb register
+**	(declared as scr0..scr3 in ncr_reg.h) just after the select/reselect,
+**	and copied back just after disconnecting.
+**	Inside the script the XX_REG are used.
+**
+**	The last four bytes are used inside the script by "COPY" commands.
+**	Because source and destination must have the same alignment
+**	in a longword, the fields HAVE to be at the choosen offsets.
+**		xerr_st	(4)	0	(0x34)	scratcha
+**		sync_st	(5)	1	(0x05)	sxfer
+**		wide_st	(7)	3	(0x03)	scntl3
+*/
+
+/*
+**	First four bytes (script)
+*/
+#define  QU_REG	scr0
+#define  HS_REG	scr1
+#define  HS_PRT	nc_scr1
+#define  SS_REG	scr2
+#define  PS_REG	scr3
+
+/*
+**	First four bytes (host)
+*/
+#define  actualquirks  phys.header.status[0]
+#define  host_status   phys.header.status[1]
+#define  scsi_status   phys.header.status[2]
+#define  parity_status phys.header.status[3]
+
+/*
+**	Last four bytes (script)
+*/
+#define  xerr_st       header.status[4]	/* MUST be ==0 mod 4 */
+#define  sync_st       header.status[5]	/* MUST be ==1 mod 4 */
+#define  nego_st       header.status[6]
+#define  wide_st       header.status[7]	/* MUST be ==3 mod 4 */
+
+/*
+**	Last four bytes (host)
+*/
+#define  xerr_status   phys.xerr_st
+#define  sync_status   phys.sync_st
+#define  nego_status   phys.nego_st
+#define  wide_status   phys.wide_st
+
+/*==========================================================
+**
+**      Declaration of structs:     Data structure block
+**
+**==========================================================
+**
+**	During execution of a ccb by the script processor,
+**	the DSA (data structure address) register points
+**	to this substructure of the ccb.
+**	This substructure contains the header with
+**	the script-processor-changable data and
+**	data blocks for the indirect move commands.
+**
+**----------------------------------------------------------
+*/
+
+struct dsb {
+
+	/*
+	**	Header.
+	**	Has to be the first entry,
+	**	because it's jumped to by the
+	**	script processor
+	*/
+
+	struct head	header;
+
+	/*
+	**	Table data for Script
+	*/
+
+	struct scr_tblsel  select;
+	struct scr_tblmove smsg  ;
+	struct scr_tblmove smsg2 ;
+	struct scr_tblmove cmd   ;
+	struct scr_tblmove scmd  ;
+	struct scr_tblmove sense ;
+	struct scr_tblmove data [MAX_SCATTER];
+};
+
+/*==========================================================
+**
+**      Declaration of structs:     Command control block.
+**
+**==========================================================
+**
+**	During execution of a ccb by the script processor,
+**	the DSA (data structure address) register points
+**	to this substructure of the ccb.
+**	This substructure contains the header with
+**	the script-processor-changable data and then
+**	data blocks for the indirect move commands.
+**
+**----------------------------------------------------------
+*/
+
+
+struct ccb {
+	/*
+	**	during reselection the ncr jumps to this point.
+	**	If a "SIMPLE_TAG" message was received,
+	**	then SFBR is set to the tag.
+	**	else SFBR is set to 0
+	**	If looking for another tag, jump to the next ccb.
+	**
+	**	JUMP  IF (SFBR != #TAG#)
+	**	@(next ccb of this lun)
+	*/
+
+	struct link		jump_ccb;
+
+	/*
+	**	After execution of this call, the return address
+	**	(in  the TEMP register) points to the following
+	**	data structure block.
+	**	So copy it to the DSA register, and start
+	**	processing of this data structure.
+	**
+	**	CALL
+	**	<RESEL_TMP>
+	*/
+
+	struct link		call_tmp;
+
+	/*
+	**	This is the data structure which is
+	**	to be executed by the script processor.
+	*/
+
+	struct dsb		phys;
+
+	/*
+	**	If a data transfer phase is terminated too early
+	**	(after reception of a message (i.e. DISCONNECT)),
+	**	we have to prepare a mini script to transfer
+	**	the rest of the data.
+	*/
+
+	ncrcmd			patch[8];
+
+	/*
+	**	The general SCSI driver provides a
+	**	pointer to a control block.
+	*/
+
+	Scsi_Cmnd	*cmd;
+	int data_len;
+
+	/*
+	**	We prepare a message to be sent after selection,
+	**	and a second one to be sent after getcc selection.
+	**      Contents are IDENTIFY and SIMPLE_TAG.
+	**	While negotiating sync or wide transfer,
+	**	a SDTM or WDTM message is appended.
+	*/
+
+	u_char			scsi_smsg [8];
+	u_char			scsi_smsg2[8];
+
+	/*
+	**	Lock this ccb.
+	**	Flag is used while looking for a free ccb.
+	*/
+
+	u_long		magic;
+
+	/*
+	**	Physical address of this instance of ccb
+	*/
+
+	u_long		p_ccb;
+
+	/*
+	**	Completion time out for this job.
+	**	It's set to time of start + allowed number of seconds.
+	*/
+
+	u_long		tlimit;
+
+	/*
+	**	All ccbs of one hostadapter are chained.
+	*/
+
+	ccb_p		link_ccb;
+
+	/*
+	**	All ccbs of one target/lun are chained.
+	*/
+
+	ccb_p		next_ccb;
+
+	/*
+	**	Sense command
+	*/
+
+	u_char		sensecmd[6];
+
+	/*
+	**	Tag for this transfer.
+	**	It's patched into jump_ccb.
+	**	If it's not zero, a SIMPLE_TAG
+	**	message is included in smsg.
+	*/
+
+	u_char			tag;
+};
+
+#define CCB_PHYS(cp,lbl)	(cp->p_ccb + offsetof(struct ccb, lbl))
+
+/*==========================================================
+**
+**      Declaration of structs:     NCR device descriptor
+**
+**==========================================================
+*/
+
+struct ncb {
+	/*-----------------------------------------------
+	**	Specific Linux fields
+	**-----------------------------------------------
+	*/
+	int    unit;			/* Unit number                       */
+	int    chip;			/* Chip number                       */
+	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               */
+#endif
+	/*-----------------------------------------------
+	**	Added field to support differences
+	**	between ncr chips.
+	**-----------------------------------------------
+	*/
+	u_short	device_id;
+	u_char	revision_id;
+#define ChipDevice	((np)->device_id)
+#define ChipVersion	((np)->revision_id & 0xf0)
+
+	/*-----------------------------------------------
+	**	Scripts ..
+	**-----------------------------------------------
+	**
+	**	During reselection the ncr jumps to this point.
+	**	The SFBR register is loaded with the encoded target id.
+	**
+	**	Jump to the first target.
+	**
+	**	JUMP
+	**	@(next tcb)
+	*/
+	struct link     jump_tcb;
+
+	/*-----------------------------------------------
+	**	Configuration ..
+	**-----------------------------------------------
+	**
+	**	virtual and physical addresses
+	**	of the 53c810 chip.
+	*/
+	vm_offset_t     vaddr;
+	vm_offset_t     paddr;
+
+	/*
+	**	pointer to the chip's registers.
+	*/
+	volatile
+	struct ncr_reg* reg;
+
+	/*
+	**	A copy of the script, relocated for this ncb.
+	*/
+	struct script	*script;
+
+	/*
+	**	Physical address of this instance of ncb->script
+	*/
+	u_long		p_script;
+
+	/*
+	**	The SCSI address of the host adapter.
+	*/
+	u_char	  myaddr;
+
+	/*
+	**	timing parameters
+	*/
+	u_char		ns_async;
+	u_char		ns_sync;
+	u_char		rv_scntl3;
+
+	/*-----------------------------------------------
+	**	Link to the generic SCSI driver
+	**-----------------------------------------------
+	*/
+
+	/* struct scsi_link	sc_link; */
+
+	/*-----------------------------------------------
+	**	Job control
+	**-----------------------------------------------
+	**
+	**	Commands from user
+	*/
+	struct usrcmd	user;
+	u_char		order;
+
+	/*
+	**	Target data
+	*/
+	struct tcb	target[MAX_TARGET];
+
+	/*
+	**	Start queue.
+	*/
+	u_long		squeue [MAX_START];
+	u_short		squeueput;
+	u_short		actccbs;
+
+	/*
+	**	Timeout handler
+	*/
+	u_long		heartbeat;
+	u_short		ticks;
+	u_short		latetime;
+	u_long		lasttime;
+
+	/*-----------------------------------------------
+	**	Debug and profiling
+	**-----------------------------------------------
+	**
+	**	register dump
+	*/
+	struct ncr_reg	regdump;
+	u_long		regtime;
+
+	/*
+	**	Profiling data
+	*/
+	struct profile	profile;
+	u_long		disc_phys;
+	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;
+
+	/*
+	**	message buffers.
+	**	Should be longword aligned,
+	**	because they're written with a
+	**	COPY script command.
+	*/
+	u_char		msgout[8];
+	u_char		msgin [8];
+	u_long		lastmsg;
+
+	/*
+	**	Buffer for STATUS_IN phase.
+	*/
+	u_char		scratch;
+
+	/*
+	**	controller chip dependent maximal transfer width.
+	*/
+	u_char		maxwide;
+
+	/*
+	**	option for M_IDENTIFY message: enables disconnecting
+	*/
+	u_char		disc;
+
+	/*
+	**	address of the ncr control registers in io space
+	*/
+	u_int		port;
+
+	/*
+	**	irq level
+	*/
+	u_short		irq;
+};
+
+#define NCB_SCRIPT_PHYS(np,lbl)	(np->p_script + offsetof (struct script, lbl))
+
+/*==========================================================
+**
+**
+**      Script for NCR-Processor.
+**
+**	Use ncr_script_fill() to create the variable parts.
+**	Use ncr_script_copy_and_bind() to make a copy and
+**	bind to physical addresses.
+**
+**
+**==========================================================
+**
+**	We have to know the offsets of all labels before
+**	we reach them (for forward jumps).
+**	Therefore we declare a struct here.
+**	If you make changes inside the script,
+**	DONT FORGET TO CHANGE THE LENGTHS HERE!
+**
+**----------------------------------------------------------
+*/
+
+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];
+	ncrcmd  idle		[  2];
+	ncrcmd	select		[ 22];
+	ncrcmd	prepare		[  4];
+	ncrcmd	loadpos		[ 14];
+	ncrcmd	prepare2	[ 24];
+	ncrcmd	setmsg		[  5];
+	ncrcmd  clrack		[  2];
+	ncrcmd  dispatch	[ 33];
+	ncrcmd	no_data		[ 17];
+	ncrcmd  checkatn	[ 10];
+	ncrcmd  command		[ 15];
+	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];
+	ncrcmd	signal		[ 10];
+	ncrcmd  save_dp		[  5];
+	ncrcmd  restore_dp	[  5];
+	ncrcmd  disconnect	[ 12];
+	ncrcmd  disconnect0	[  5];
+	ncrcmd  disconnect1	[ 23];
+	ncrcmd	msg_out		[  9];
+	ncrcmd	msg_out_done	[  7];
+	ncrcmd	msg_out_abort	[ 10];
+	ncrcmd  getcc		[  4];
+	ncrcmd  getcc1		[  5];
+#ifdef NCR_GETCC_WITHMSG
+	ncrcmd	getcc2		[ 33];
+#else
+	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	aborttag	[  4];
+	ncrcmd	abort		[ 22];
+	ncrcmd	snooptest	[  9];
+	ncrcmd	snoopend	[  2];
+};
+
+/*==========================================================
+**
+**
+**      Function headers.
+**
+**
+**==========================================================
+*/
+
+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);
+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	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);
+
+#ifdef SCSI_NCR_PROFILE
+static	int	ncr_delta	(u_long from, u_long to);
+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);
+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_settags     (tcb_p tp, lcb_p lp);
+static	void	ncr_setwide	(ncb_p np, ccb_p cp, u_char wide);
+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);
+
+#ifdef SCSI_NCR_USER_COMMAND
+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 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 void process_waiting_list(ncb_p np, int sts);
+
+#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)
+
+/*==========================================================
+**
+**
+**      Global static data.
+**
+**
+**==========================================================
+*/
+
+#if 0
+static char ident[] =
+ 	"\n$Id: ncr.c,v 1.67 1996/03/11 19:36:07 se Exp $\n";
+static u_long	ncr_version = NCR_VERSION	* 11
+	+ (u_long) sizeof (struct ncb)	*  7
+	+ (u_long) sizeof (struct ccb)	*  5
+	+ (u_long) sizeof (struct lcb)	*  3
+	+ (u_long) sizeof (struct tcb)	*  2;
+#endif
+
+#ifdef SCSI_NCR_DEBUG
+static int ncr_debug = SCSI_NCR_DEBUG_FLAGS;
+#endif
+
+/*==========================================================
+**
+**
+**      Global static data:	auto configure
+**
+**
+**==========================================================
+*/
+
+static char *ncr_name (ncb_p np)
+{
+	static char name[10];
+	sprintf(name, "ncr53c%d-%d", np->chip, np->unit);
+	return (name);
+}
+
+
+/*==========================================================
+**
+**
+**      Scripts for NCR-Processor.
+**
+**      Use ncr_script_bind for binding to physical addresses.
+**
+**
+**==========================================================
+**
+**	NADDR generates a reference to a field of the controller data.
+**	PADDR generates a reference to another part of the script.
+**	RADDR generates a reference to a script processor register.
+**	FADDR generates a reference to a script processor register
+**		with offset.
+**
+**----------------------------------------------------------
+*/
+
+#define	RELOC_SOFTC	0x40000000
+#define	RELOC_LABEL	0x50000000
+#define	RELOC_REGISTER	0x60000000
+#define	RELOC_KVAR	0x70000000
+#define	RELOC_MASK	0xf0000000
+
+#define	NADDR(label)	(RELOC_SOFTC | offsetof(struct ncb, label))
+#define PADDR(label)    (RELOC_LABEL | offsetof(struct script, label))
+#define	RADDR(label)	(RELOC_REGISTER | REG(label))
+#define	FADDR(label,ofs)(RELOC_REGISTER | ((REG(label))+(ofs)))
+#define	KVAR(which)	(RELOC_KVAR | (which))
+
+#define	SCRIPT_KVAR_JIFFIES	(0)
+
+#define	SCRIPT_KVAR_FIRST		SCRIPT_KVAR_JIFFIES
+#define	SCRIPT_KVAR_LAST		SCRIPT_KVAR_JIFFIES
+
+/*
+ * Kernel variables referenced in the scripts.
+ * THESE MUST ALL BE ALIGNED TO A 4-BYTE BOUNDARY.
+ */
+static void *script_kvars[] =
+	{ (void *)&jiffies };
+
+static	struct script script0 = {
+/*--------------------------< START >-----------------------*/ {
+	/*
+	**	Claim to be still alive ...
+	*/
+	SCR_COPY (sizeof (((struct ncb *)0)->heartbeat)),
+		KVAR(SCRIPT_KVAR_JIFFIES),
+		NADDR (heartbeat),
+
+	/*
+	**      Make data structure address invalid.
+	**      clear SIGP.
+	*/
+	SCR_LOAD_REG (dsa, 0xff),
+		0,
+	SCR_FROM_REG (ctest2),
+		0,
+}/*-------------------------< START0 >----------------------*/,{
+	/*
+	**	Hook for interrupted GetConditionCode.
+	**	Will be patched to ... IFTRUE by
+	**	the interrupt handler.
+	*/
+	SCR_INT ^ IFFALSE (0),
+		SIR_SENSE_RESTART,
+
+}/*-------------------------< START1 >----------------------*/,{
+	/*
+	**	Hook for stalled start queue.
+	**	Will be patched to IFTRUE by the interrupt handler.
+	*/
+	SCR_INT ^ IFFALSE (0),
+		SIR_STALL_RESTART,
+	/*
+	**	Then jump to a certain point in tryloop.
+	**	Due to the lack of indirect addressing the code
+	**	is self modifying here.
+	*/
+	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
+
+}/*-------------------------< TRYSEL >----------------------*/,{
+	/*
+	**	Now:
+	**	DSA: Address of a Data Structure
+	**	or   Address of the IDLE-Label.
+	**
+	**	TEMP:	Address of a script, which tries to
+	**		start the NEXT entry.
+	**
+	**	Save the TEMP register into the SCRATCHA register.
+	**	Then copy the DSA to TEMP and RETURN.
+	**	This is kind of an indirect jump.
+	**	(The script processor has NO stack, so the
+	**	CALL is actually a jump and link, and the
+	**	RETURN is an indirect jump.)
+	**
+	**	If the slot was empty, DSA contains the address
+	**	of the IDLE part of this script. The processor
+	**	jumps to IDLE and waits for a reselect.
+	**	It will wake up and try the same slot again
+	**	after the SIGP bit becomes set by the host.
+	**
+	**	If the slot was not empty, DSA contains
+	**	the address of the phys-part of a ccb.
+	**	The processor jumps to this address.
+	**	phys starts with head,
+	**	head starts with launch,
+	**	so actually the processor jumps to
+	**	the lauch part.
+	**	If the entry is scheduled for execution,
+	**	then launch contains a jump to SELECT.
+	**	If it's not scheduled, it contains a jump to IDLE.
+	*/
+	SCR_COPY (4),
+		RADDR (temp),
+		RADDR (scratcha),
+	SCR_COPY (4),
+		RADDR (dsa),
+		RADDR (temp),
+	SCR_RETURN,
+		0
+
+}/*-------------------------< SKIP >------------------------*/,{
+	/*
+	**	This entry has been canceled.
+	**	Next time use the next slot.
+	*/
+	SCR_COPY (4),
+		RADDR (scratcha),
+		PADDR (startpos),
+	/*
+	**	patch the launch field.
+	**	should look like an idle process.
+	*/
+	SCR_COPY (4),
+		RADDR (dsa),
+		PADDR (skip2),
+	SCR_COPY (8),
+		PADDR (idle),
+}/*-------------------------< SKIP2 >-----------------------*/,{
+		0,
+	SCR_JUMP,
+		PADDR(start),
+}/*-------------------------< IDLE >------------------------*/,{
+	/*
+	**	Nothing to do?
+	**	Wait for reselect.
+	*/
+	SCR_JUMP,
+		PADDR(reselect),
+
+}/*-------------------------< SELECT >----------------------*/,{
+	/*
+	**	DSA	contains the address of a scheduled
+	**		data structure.
+	**
+	**	SCRATCHA contains the address of the script,
+	**		which starts the next entry.
+	**
+	**	Set Initiator mode.
+	**
+	**	(Target mode is left as an exercise for the reader)
+	*/
+
+	SCR_CLR (SCR_TRG),
+		0,
+	SCR_LOAD_REG (HS_REG, 0xff),
+		0,
+
+	/*
+	**      And try to select this target.
+	*/
+	SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select),
+		PADDR (reselect),
+
+	/*
+	**	Now there are 4 possibilities:
+	**
+	**	(1) The ncr looses arbitration.
+	**	This is ok, because it will try again,
+	**	when the bus becomes idle.
+	**	(But beware of the timeout function!)
+	**
+	**	(2) The ncr is reselected.
+	**	Then the script processor takes the jump
+	**	to the RESELECT label.
+	**
+	**	(3) The ncr completes the selection.
+	**	Then it will execute the next statement.
+	**
+	**	(4) There is a selection timeout.
+	**	Then the ncr should interrupt the host and stop.
+	**	Unfortunately, it seems to continue execution
+	**	of the script. But it will fail with an
+	**	IID-interrupt on the next WHEN.
+	*/
+
+	SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_IN)),
+		0,
+
+	/*
+	**	Save target id to ctest0 register
+	*/
+
+	SCR_FROM_REG (sdid),
+		0,
+	SCR_TO_REG (ctest0),
+		0,
+	/*
+	**	Send the IDENTIFY and SIMPLE_TAG messages
+	**	(and the M_X_SYNC_REQ message)
+	*/
+	SCR_MOVE_TBL ^ SCR_MSG_OUT,
+		offsetof (struct dsb, smsg),
+#ifdef undef /* XXX better fail than try to deal with this ... */
+	SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+		-16,
+#endif
+	SCR_CLR (SCR_ATN),
+		0,
+	SCR_COPY (1),
+		RADDR (sfbr),
+		NADDR (lastmsg),
+	/*
+	**	Selection complete.
+	**	Next time use the next slot.
+	*/
+	SCR_COPY (4),
+		RADDR (scratcha),
+		PADDR (startpos),
+}/*-------------------------< PREPARE >----------------------*/,{
+	/*
+	**      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 access it.
+	**
+	**	We patch the address part of a
+	**	COPY command with the DSA-register.
+	*/
+	SCR_COPY (4),
+		RADDR (dsa),
+		PADDR (loadpos),
+	/*
+	**	then we do the actual copy.
+	*/
+	SCR_COPY (sizeof (struct head)),
+	/*
+	**	continued after the next label ...
+	*/
+
+}/*-------------------------< LOADPOS >---------------------*/,{
+		0,
+		NADDR (header),
+	/*
+	**      Mark this ccb as not scheduled.
+	*/
+	SCR_COPY (8),
+		PADDR (idle),
+		NADDR (header.launch),
+	/*
+	**      Set a time stamp for this selection
+	*/
+	SCR_COPY (sizeof (u_long)),
+		KVAR(SCRIPT_KVAR_JIFFIES),
+		NADDR (header.stamp.select),
+	/*
+	**      load the savep (saved pointer) into
+	**      the TEMP register (actual pointer)
+	*/
+	SCR_COPY (4),
+		NADDR (header.savep),
+		RADDR (temp),
+	/*
+	**      Initialize the status registers
+	*/
+	SCR_COPY (4),
+		NADDR (header.status),
+		RADDR (scr0),
+
+}/*-------------------------< PREPARE2 >---------------------*/,{
+	/*
+	**      Load the synchronous mode register
+	*/
+	SCR_COPY (1),
+		NADDR (sync_st),
+		RADDR (sxfer),
+	/*
+	**      Load the wide mode and timing register
+	*/
+	SCR_COPY (1),
+		NADDR (wide_st),
+		RADDR (scntl3),
+	/*
+	**	Initialize the msgout buffer with a NOOP message.
+	*/
+	SCR_LOAD_REG (scratcha, M_NOOP),
+		0,
+	SCR_COPY (1),
+		RADDR (scratcha),
+		NADDR (msgout),
+	SCR_COPY (1),
+		RADDR (scratcha),
+		NADDR (msgin),
+	/*
+	**	Message in phase ?
+	*/
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR (dispatch),
+	/*
+	**	Extended or reject message ?
+	*/
+	SCR_FROM_REG (sbdl),
+		0,
+	SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
+		PADDR (msg_in),
+	SCR_JUMP ^ IFTRUE (DATA (M_REJECT)),
+		PADDR (msg_reject),
+	/*
+	**	normal processing
+	*/
+	SCR_JUMP,
+		PADDR (dispatch),
+}/*-------------------------< SETMSG >----------------------*/,{
+	SCR_COPY (1),
+		RADDR (scratcha),
+		NADDR (msgout),
+	SCR_SET (SCR_ATN),
+		0,
+}/*-------------------------< CLRACK >----------------------*/,{
+	/*
+	**	Terminate possible pending message phase.
+	*/
+	SCR_CLR (SCR_ACK),
+		0,
+
+}/*-----------------------< DISPATCH >----------------------*/,{
+	SCR_FROM_REG (HS_REG),
+		0,
+	SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
+		SIR_NEGO_FAILED,
+	/*
+	**	remove bogus output signals
+	*/
+	SCR_REG_REG (socl, SCR_AND, CACK|CATN),
+		0,
+	SCR_RETURN ^ IFTRUE (WHEN (SCR_DATA_OUT)),
+		0,
+	SCR_RETURN ^ IFTRUE (IF (SCR_DATA_IN)),
+		0,
+	SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)),
+		PADDR (msg_out),
+	SCR_JUMP ^ IFTRUE (IF (SCR_MSG_IN)),
+		PADDR (msg_in),
+	SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)),
+		PADDR (command),
+	SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)),
+		PADDR (status),
+	/*
+	**      Discard one illegal phase byte, if required.
+	*/
+	SCR_LOAD_REG (scratcha, XE_BAD_PHASE),
+		0,
+	SCR_COPY (1),
+		RADDR (scratcha),
+		NADDR (xerr_st),
+	SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_OUT)),
+		8,
+	SCR_MOVE_ABS (1) ^ SCR_ILG_OUT,
+		NADDR (scratch),
+	SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_IN)),
+		8,
+	SCR_MOVE_ABS (1) ^ SCR_ILG_IN,
+		NADDR (scratch),
+	SCR_JUMP,
+		PADDR (dispatch),
+
+}/*-------------------------< NO_DATA >--------------------*/,{
+	/*
+	**	The target wants to tranfer too much data
+	**	or in the wrong direction.
+	**      Remember that in extended error.
+	*/
+	SCR_LOAD_REG (scratcha, XE_EXTRA_DATA),
+		0,
+	SCR_COPY (1),
+		RADDR (scratcha),
+		NADDR (xerr_st),
+	/*
+	**      Discard one data byte, if required.
+	*/
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)),
+		8,
+	SCR_MOVE_ABS (1) ^ SCR_DATA_OUT,
+		NADDR (scratch),
+	SCR_JUMPR ^ IFFALSE (IF (SCR_DATA_IN)),
+		8,
+	SCR_MOVE_ABS (1) ^ SCR_DATA_IN,
+		NADDR (scratch),
+	/*
+	**      .. and repeat as required.
+	*/
+	SCR_CALL,
+		PADDR (dispatch),
+	SCR_JUMP,
+		PADDR (no_data),
+}/*-------------------------< CHECKATN >--------------------*/,{
+	/*
+	**	If AAP (bit 1 of scntl0 register) is set
+	**	and a parity error is detected,
+	**	the script processor asserts ATN.
+	**
+	**	The target should switch to a MSG_OUT phase
+	**	to get the message.
+	*/
+	SCR_FROM_REG (socl),
+		0,
+	SCR_JUMP ^ IFFALSE (MASK (CATN, CATN)),
+		PADDR (dispatch),
+	/*
+	**	count it
+	*/
+	SCR_REG_REG (PS_REG, SCR_ADD, 1),
+		0,
+	/*
+	**	Prepare a M_ID_ERROR message
+	**	(initiator detected error).
+	**	The target should retry the transfer.
+	*/
+	SCR_LOAD_REG (scratcha, M_ID_ERROR),
+		0,
+	SCR_JUMP,
+		PADDR (setmsg),
+
+}/*-------------------------< COMMAND >--------------------*/,{
+	/*
+	**	If this is not a GETCC transfer ...
+	*/
+	SCR_FROM_REG (SS_REG),
+		0,
+/*<<<*/	SCR_JUMPR ^ IFTRUE (DATA (S_CHECK_COND)),
+		28,
+	/*
+	**	... set a timestamp ...
+	*/
+	SCR_COPY (sizeof (u_long)),
+		KVAR(SCRIPT_KVAR_JIFFIES),
+		NADDR (header.stamp.command),
+	/*
+	**	... and send the command
+	*/
+	SCR_MOVE_TBL ^ SCR_COMMAND,
+		offsetof (struct dsb, cmd),
+	SCR_JUMP,
+		PADDR (dispatch),
+	/*
+	**	Send the GETCC command
+	*/
+/*>>>*/	SCR_MOVE_TBL ^ SCR_COMMAND,
+		offsetof (struct dsb, scmd),
+	SCR_JUMP,
+		PADDR (dispatch),
+
+}/*-------------------------< STATUS >--------------------*/,{
+	/*
+	**	set the timestamp.
+	*/
+	SCR_COPY (sizeof (u_long)),
+		KVAR(SCRIPT_KVAR_JIFFIES),
+		NADDR (header.stamp.status),
+	/*
+	**	If this is a GETCC transfer,
+	*/
+	SCR_FROM_REG (SS_REG),
+		0,
+/*<<<*/	SCR_JUMPR ^ IFFALSE (DATA (S_CHECK_COND)),
+		40,
+	/*
+	**	get the status
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_STATUS,
+		NADDR (scratch),
+	/*
+	**	Save status to scsi_status.
+	**	Mark as complete.
+	**	And wait for disconnect.
+	*/
+	SCR_TO_REG (SS_REG),
+		0,
+	SCR_REG_REG (SS_REG, SCR_OR, S_SENSE),
+		0,
+	SCR_LOAD_REG (HS_REG, HS_COMPLETE),
+		0,
+	SCR_JUMP,
+		PADDR (checkatn),
+	/*
+	**	If it was no GETCC transfer,
+	**	save the status to scsi_status.
+	*/
+/*>>>*/	SCR_MOVE_ABS (1) ^ SCR_STATUS,
+		NADDR (scratch),
+	SCR_TO_REG (SS_REG),
+		0,
+	/*
+	**	if it was no check condition ...
+	*/
+	SCR_JUMP ^ IFTRUE (DATA (S_CHECK_COND)),
+		PADDR (checkatn),
+	/*
+	**	... mark as complete.
+	*/
+	SCR_LOAD_REG (HS_REG, HS_COMPLETE),
+		0,
+	SCR_JUMP,
+		PADDR (checkatn),
+
+}/*-------------------------< MSG_IN >--------------------*/,{
+	/*
+	**	Get the first byte of the message
+	**	and save it to SCRATCHA.
+	**
+	**	The script processor doesn't negate the
+	**	ACK signal after this transfer.
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin[0]),
+	/*
+	**	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,
+	/*
+	**	Parity was ok, handle this message.
+	*/
+	SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)),
+		PADDR (complete),
+	SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)),
+		PADDR (save_dp),
+	SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)),
+		PADDR (restore_dp),
+	SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)),
+		PADDR (disconnect),
+	SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
+		PADDR (msg_extended),
+	SCR_JUMP ^ IFTRUE (DATA (M_NOOP)),
+		PADDR (clrack),
+	SCR_JUMP ^ IFTRUE (DATA (M_REJECT)),
+		PADDR (msg_reject),
+	SCR_JUMP ^ IFTRUE (DATA (M_IGN_RESIDUE)),
+		PADDR (msg_ign_residue),
+	/*
+	**	Rest of the messages left as
+	**	an exercise ...
+	**
+	**	Unimplemented messages:
+	**	fall through to MSG_BAD.
+	*/
+}/*-------------------------< MSG_BAD >------------------*/,{
+	/*
+	**	unimplemented message - reject it.
+	*/
+	SCR_INT,
+		SIR_REJECT_SENT,
+	SCR_LOAD_REG (scratcha, M_REJECT),
+		0,
+	SCR_JUMP,
+		PADDR (setmsg),
+
+}/*-------------------------< 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)),
+		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 >-------------------*/,{
+	/*
+	**      dsa:    Pointer to ccb
+	**	      or xxxxxxFF (no ccb)
+	**
+	**      HS_REG:   Host-Status (<>0!)
+	*/
+	SCR_FROM_REG (dsa),
+		0,
+	SCR_JUMP ^ IFTRUE (DATA (0xff)),
+		PADDR (signal),
+	/*
+	**      dsa is valid.
+	**	save the status registers
+	*/
+	SCR_COPY (4),
+		RADDR (scr0),
+		NADDR (header.status),
+	/*
+	**	and copy back the header to the ccb.
+	*/
+	SCR_COPY (4),
+		RADDR (dsa),
+		PADDR (cleanup0),
+	SCR_COPY (sizeof (struct head)),
+		NADDR (header),
+}/*-------------------------< CLEANUP0 >--------------------*/,{
+		0,
+
+	/*
+	**	If command resulted in "check condition"
+	**	status and is not yet completed,
+	**	try to get the condition code.
+	*/
+	SCR_FROM_REG (HS_REG),
+		0,
+/*<<<*/	SCR_JUMPR ^ IFFALSE (MASK (0, HS_DONEMASK)),
+		16,
+	SCR_FROM_REG (SS_REG),
+		0,
+	SCR_JUMP ^ IFTRUE (DATA (S_CHECK_COND)),
+		PADDR(getcc2),
+	/*
+	**	And make the DSA register invalid.
+	*/
+/*>>>*/	SCR_LOAD_REG (dsa, 0xff), /* invalid */
+		0,
+}/*-------------------------< SIGNAL >----------------------*/,{
+	/*
+	**	if status = queue full,
+	**	reinsert in startqueue and stall queue.
+	*/
+	SCR_FROM_REG (SS_REG),
+		0,
+	SCR_INT ^ IFTRUE (DATA (S_QUEUE_FULL)),
+		SIR_STALL_QUEUE,
+	/*
+	**	if job completed ...
+	*/
+	SCR_FROM_REG (HS_REG),
+		0,
+	/*
+	**	... signal completion to the host
+	*/
+	SCR_INT_FLY ^ IFFALSE (MASK (0, HS_DONEMASK)),
+		0,
+	/*
+	**	Auf zu neuen Schandtaten!
+	*/
+	SCR_JUMP,
+		PADDR(start),
+
+}/*-------------------------< SAVE_DP >------------------*/,{
+	/*
+	**	SAVE_DP message:
+	**	Copy TEMP register to SAVEP in header.
+	*/
+	SCR_COPY (4),
+		RADDR (temp),
+		NADDR (header.savep),
+	SCR_JUMP,
+		PADDR (clrack),
+}/*-------------------------< RESTORE_DP >---------------*/,{
+	/*
+	**	RESTORE_DP message:
+	**	Copy SAVEP in header to TEMP register.
+	*/
+	SCR_COPY (4),
+		NADDR (header.savep),
+		RADDR (temp),
+	SCR_JUMP,
+		PADDR (clrack),
+
+}/*-------------------------< DISCONNECT >---------------*/,{
+	/*
+	**	If QUIRK_AUTOSAVE is set,
+	**	do an "save pointer" operation.
+	*/
+	SCR_FROM_REG (QU_REG),
+		0,
+/*<<<*/	SCR_JUMPR ^ IFFALSE (MASK (QUIRK_AUTOSAVE, QUIRK_AUTOSAVE)),
+		12,
+	/*
+	**	like SAVE_DP message:
+	**	Copy TEMP register to SAVEP in header.
+	*/
+	SCR_COPY (4),
+		RADDR (temp),
+		NADDR (header.savep),
+/*>>>*/	/*
+	**	Check if temp==savep or temp==goalp:
+	**	if not, log a missing save pointer message.
+	**	In fact, it's a comparison mod 256.
+	**
+	**	Hmmm, I hadn't thought that I would be urged to
+	**	write this kind of ugly self modifying code.
+	**
+	**	It's unbelievable, but the ncr53c8xx isn't able
+	**	to subtract one register from another.
+	*/
+	SCR_FROM_REG (temp),
+		0,
+	/*
+	**	You are not expected to understand this ..
+	**
+	**	CAUTION: only little endian architectures supported! XXX
+	*/
+	SCR_COPY (1),
+		NADDR (header.savep),
+		PADDR (disconnect0),
+}/*-------------------------< DISCONNECT0 >--------------*/,{
+/*<<<*/	SCR_JUMPR ^ IFTRUE (DATA (1)),
+		20,
+	/*
+	**	neither this
+	*/
+	SCR_COPY (1),
+		NADDR (header.goalp),
+		PADDR (disconnect1),
+}/*-------------------------< DISCONNECT1 >--------------*/,{
+	SCR_INT ^ IFFALSE (DATA (1)),
+		SIR_MISSING_SAVE,
+/*>>>*/
+
+	/*
+	**	DISCONNECTing  ...
+	**
+	**	disable the "unexpected disconnect" feature,
+	**	and remove the ACK signal.
+	*/
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+		0,
+	SCR_CLR (SCR_ACK|SCR_ATN),
+		0,
+	/*
+	**	Wait for the disconnect.
+	*/
+	SCR_WAIT_DISC,
+		0,
+	/*
+	**	Profiling:
+	**	Set a time stamp,
+	**	and count the disconnects.
+	*/
+	SCR_COPY (sizeof (u_long)),
+		KVAR(SCRIPT_KVAR_JIFFIES),
+		NADDR (header.stamp.disconnect),
+	SCR_COPY (4),
+		NADDR (disc_phys),
+		RADDR (temp),
+	SCR_REG_REG (temp, SCR_ADD, 0x01),
+		0,
+	SCR_COPY (4),
+		RADDR (temp),
+		NADDR (disc_phys),
+	/*
+	**	Status is: DISCONNECTED.
+	*/
+	SCR_LOAD_REG (HS_REG, HS_DISCONNECT),
+		0,
+	SCR_JUMP,
+		PADDR (cleanup),
+
+}/*-------------------------< MSG_OUT >-------------------*/,{
+	/*
+	**	The target requests a message.
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
+		NADDR (msgout),
+	SCR_COPY (1),
+		RADDR (sfbr),
+		NADDR (lastmsg),
+	/*
+	**	If it was no ABORT message ...
+	*/
+	SCR_JUMP ^ IFTRUE (DATA (M_ABORT)),
+		PADDR (msg_out_abort),
+	/*
+	**	... wait for the next phase
+	**	if it's a message out, send it again, ...
+	*/
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+		PADDR (msg_out),
+}/*-------------------------< MSG_OUT_DONE >--------------*/,{
+	/*
+	**	... else clear the message ...
+	*/
+	SCR_LOAD_REG (scratcha, M_NOOP),
+		0,
+	SCR_COPY (4),
+		RADDR (scratcha),
+		NADDR (msgout),
+	/*
+	**	... and process the next phase
+	*/
+	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 >---------------------*/,{
+	/*
+	**	If SIGP was set, clear it and try again.
+	*/
+	SCR_FROM_REG (ctest2),
+		0,
+	SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)),
+		PADDR (getcc2),
+	SCR_INT,
+		SIR_SENSE_FAILED,
+}/*-------------------------< RESELECT >--------------------*/,{
+	/*
+	**	make the DSA invalid.
+	*/
+	SCR_LOAD_REG (dsa, 0xff),
+		0,
+	SCR_CLR (SCR_TRG),
+		0,
+	/*
+	**	Sleep waiting for a reselection.
+	**	If SIGP is set, special treatment.
+	**
+	**	Zu allem bereit ..
+	*/
+	SCR_WAIT_RESEL,
+		PADDR(reselect2),
+	/*
+	**	... zu nichts zu gebrauchen ?
+	**
+	**      load the target id into the SFBR
+	**	and jump to the control block.
+	**
+	**	Look at the declarations of
+	**	- struct ncb
+	**	- struct tcb
+	**	- struct lcb
+	**	- struct ccb
+	**	to understand what's going on.
+	*/
+	SCR_REG_SFBR (ssid, SCR_AND, 0x87),
+		0,
+	SCR_TO_REG (ctest0),
+		0,
+	SCR_JUMP,
+		NADDR (jump_tcb),
+}/*-------------------------< RESELECT2 >-------------------*/,{
+	/*
+	**	If it's not connected :(
+	**	-> interrupted by SIGP bit.
+	**	Jump to start.
+	*/
+	SCR_FROM_REG (ctest2),
+		0,
+	SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)),
+		PADDR (start),
+	SCR_JUMP,
+		PADDR (reselect),
+
+}/*-------------------------< RESEL_TMP >-------------------*/,{
+	/*
+	**	The return address in TEMP
+	**	is in fact the data structure address,
+	**	so copy it to the DSA register.
+	*/
+	SCR_COPY (4),
+		RADDR (temp),
+		RADDR (dsa),
+	SCR_JUMP,
+		PADDR (prepare),
+
+}/*-------------------------< RESEL_LUN >-------------------*/,{
+	/*
+	**	come back to this point
+	**	to get an IDENTIFY message
+	**	Wait for a msg_in phase.
+	*/
+/*<<<*/	SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		48,
+	/*
+	**	message phase
+	**	It's not a sony, it's a trick:
+	**	read the data without acknowledging it.
+	*/
+	SCR_FROM_REG (sbdl),
+		0,
+/*<<<*/	SCR_JUMPR ^ IFFALSE (MASK (M_IDENTIFY, 0x98)),
+		32,
+	/*
+	**	It WAS an Identify message.
+	**	get it and ack it!
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin),
+	SCR_CLR (SCR_ACK),
+		0,
+	/*
+	**	Mask out the lun.
+	*/
+	SCR_REG_REG (sfbr, SCR_AND, 0x07),
+		0,
+	SCR_RETURN,
+		0,
+	/*
+	**	No message phase or no IDENTIFY message:
+	**	return 0.
+	*/
+/*>>>*/	SCR_LOAD_SFBR (0),
+		0,
+	SCR_RETURN,
+		0,
+
+}/*-------------------------< RESEL_TAG >-------------------*/,{
+	/*
+	**	come back to this point
+	**	to get a SIMPLE_TAG message
+	**	Wait for a MSG_IN phase.
+	*/
+/*<<<*/	SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		64,
+	/*
+	**	message phase
+	**	It's a trick - read the data
+	**	without acknowledging it.
+	*/
+	SCR_FROM_REG (sbdl),
+		0,
+/*<<<*/	SCR_JUMPR ^ IFFALSE (DATA (M_SIMPLE_TAG)),
+		48,
+	/*
+	**	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_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 >=========
+**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
+**  ||		PADDR (dispatch),
+**  ||	SCR_MOVE_TBL ^ SCR_DATA_OUT,
+**  ||		offsetof (struct dsb, data[ i]),
+**  ##==========================================
+**
+**	SCR_CALL,
+**		PADDR (dispatch),
+**	SCR_JUMP,
+**		PADDR (no_data),
+**
+**---------------------------------------------------------
+*/
+0	/* was (u_long)&ident ? */
+
+}/*-------------------------< ABORTTAG >-------------------*/,{
+	/*
+	**      Abort a bad reselection.
+	**	Set the message to ABORT vs. ABORT_TAG
+	*/
+	SCR_LOAD_REG (scratcha, M_ABORT_TAG),
+		0,
+	SCR_JUMPR ^ IFFALSE (CARRYSET),
+		8,
+}/*-------------------------< ABORT >----------------------*/,{
+	SCR_LOAD_REG (scratcha, M_ABORT),
+		0,
+	SCR_COPY (1),
+		RADDR (scratcha),
+		NADDR (msgout),
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_CLR (SCR_ACK),
+		0,
+	/*
+	**	and send it.
+	**	we expect an immediate disconnect
+	*/
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+		0,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
+		NADDR (msgout),
+	SCR_COPY (1),
+		RADDR (sfbr),
+		NADDR (lastmsg),
+	SCR_CLR (SCR_ACK|SCR_ATN),
+		0,
+	SCR_WAIT_DISC,
+		0,
+	SCR_JUMP,
+		PADDR (start),
+}/*-------------------------< SNOOPTEST >-------------------*/,{
+	/*
+	**	Read the variable.
+	*/
+	SCR_COPY (4),
+		NADDR(ncr_cache),
+		RADDR (scratcha),
+	/*
+	**	Write the variable.
+	*/
+	SCR_COPY (4),
+		RADDR (temp),
+		NADDR(ncr_cache),
+	/*
+	**	Read back the variable.
+	*/
+	SCR_COPY (4),
+		NADDR(ncr_cache),
+		RADDR (temp),
+}/*-------------------------< SNOOPEND >-------------------*/,{
+	/*
+	**	And stop.
+	*/
+	SCR_INT,
+		99,
+}/*--------------------------------------------------------*/
+};
+
+/*==========================================================
+**
+**
+**	Fill in #define dependent parts of the script
+**
+**
+**==========================================================
+*/
+
+void ncr_script_fill (struct script * scr)
+{
+	int	i;
+	ncrcmd	*p;
+
+	p = scr->tryloop;
+	for (i=0; i<MAX_START; i++) {
+		*p++ =SCR_COPY (4);
+		*p++ =NADDR (squeue[i]);
+		*p++ =RADDR (dsa);
+		*p++ =SCR_CALL;
+		*p++ =PADDR (trysel);
+	};
+	*p++ =SCR_JUMP;
+	*p++ =PADDR(tryloop);
+
+	assert ((u_long)p == (u_long)&scr->tryloop + sizeof (scr->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++) {
+		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
+		*p++ =PADDR (checkatn);
+		*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
+		*p++ =offsetof (struct dsb, data[i]);
+	};
+
+	*p++ =SCR_CALL;
+	*p++ =PADDR (checkatn);
+	*p++ =SCR_JUMP;
+	*p++ =PADDR (no_data);
+
+	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]);
+
+	for (i=1; i<MAX_SCATTER; i++) {
+		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
+		*p++ =PADDR (dispatch);
+		*p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
+		*p++ =offsetof (struct dsb, data[i]);
+	};
+
+	*p++ =SCR_CALL;
+	*p++ =PADDR (dispatch);
+	*p++ =SCR_JUMP;
+	*p++ =PADDR (no_data);
+
+	assert ((u_long)p == (u_long)&scr->data_out + sizeof (scr->data_out));
+}
+
+/*==========================================================
+**
+**
+**	Copy and rebind a script.
+**
+**
+**==========================================================
+*/
+
+static void ncr_script_copy_and_bind (struct script *script, ncb_p np)
+{
+	ncrcmd  opcode, new, old, tmp1, tmp2;
+	ncrcmd	*src, *dst, *start, *end;
+	int relocs;
+
+	np->p_script = vtophys(np->script);
+
+	src = script->start;
+	dst = np->script->start;
+
+	start = src;
+	end = src + (sizeof (struct script) / 4);
+
+	while (src < end) {
+
+		*dst++ = opcode = *src++;
+
+		/*
+		**	If we forget to change the length
+		**	in struct script, a field will be
+		**	padded with 0. This is an illegal
+		**	command.
+		*/
+
+		if (opcode == 0) {
+			printf ("%s: ERROR0 IN SCRIPT at %d.\n",
+				ncr_name(np), (int) (src-start-1));
+			DELAY (1000000);
+		};
+
+		if (DEBUG_FLAGS & DEBUG_SCRIPT)
+			printf ("%p:  <%x>\n",
+				(src-1), (unsigned)opcode);
+
+		/*
+		**	We don't have to decode ALL commands
+		*/
+		switch (opcode >> 28) {
+
+		case 0xc:
+			/*
+			**	COPY has TWO arguments.
+			*/
+			relocs = 2;
+			tmp1 = src[0];
+			if ((tmp1 & RELOC_MASK) == RELOC_KVAR)
+				tmp1 = 0;
+			tmp2 = src[1];
+			if ((tmp2 & RELOC_MASK) == RELOC_KVAR)
+				tmp2 = 0;
+			if ((tmp1 ^ tmp2) & 3) {
+				printf ("%s: ERROR1 IN SCRIPT at %d.\n",
+					ncr_name(np), (int) (src-start-1));
+				DELAY (1000000);
+			}
+			break;
+
+		case 0x0:
+			/*
+			**	MOVE (absolute address)
+			*/
+			relocs = 1;
+			break;
+
+		case 0x8:
+			/*
+			**	JUMP / CALL
+			**	dont't relocate if relative :-)
+			*/
+			if (opcode & 0x00800000)
+				relocs = 0;
+			else
+				relocs = 1;
+			break;
+
+		case 0x4:
+		case 0x5:
+		case 0x6:
+		case 0x7:
+			relocs = 1;
+			break;
+
+		default:
+			relocs = 0;
+			break;
+		};
+
+		if (relocs) {
+			while (relocs--) {
+				old = *src++;
+
+				switch (old & RELOC_MASK) {
+				case RELOC_REGISTER:
+					new = (old & ~RELOC_MASK) + np->paddr;
+					break;
+				case RELOC_LABEL:
+					new = (old & ~RELOC_MASK) + np->p_script;
+					break;
+				case RELOC_SOFTC:
+					new = (old & ~RELOC_MASK) + vtophys(np);
+					break;
+				case RELOC_KVAR:
+					if (((old & ~RELOC_MASK) <
+					     SCRIPT_KVAR_FIRST) ||
+					    ((old & ~RELOC_MASK) >
+					     SCRIPT_KVAR_LAST))
+						panic("ncr KVAR out of range");
+					new = vtophys(script_kvars[old &
+					    ~RELOC_MASK]);
+					break;
+				case 0:
+					/* Don't relocate a 0 address. */
+					if (old == 0) {
+						new = old;
+						break;
+					}
+					/* fall through */
+				default:
+					panic("ncr_script_copy_and_bind: weird relocation %x\n", old);
+					break;
+				}
+
+				*dst++ = new;
+			}
+		} else
+			*dst++ = *src++;
+
+	};
+}
+
+/*==========================================================
+**
+**
+**      Auto configuration:  attach and init a host adapter.
+**
+**
+**==========================================================
+*/
+
+#define	MIN_ASYNC_PD	40
+#define	MIN_SYNC_PD	20
+
+
+/*
+**	Linux host data structure
+**
+**	The script area is allocated in the host data structure
+**	because kmalloc() returns NULL during scsi initialisations
+**	with Linux 1.2.X
+*/
+
+struct host_data {
+     struct ncb ncb_data;
+     struct script script_data;
+};
+
+/*
+**	Print something which allow to retreive 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))
+
+static inline void PRINT_ADDR(Scsi_Cmnd *cmd)
+{
+	struct host_data *host_data = (struct host_data *) cmd->host->hostdata;
+	ncb_p np                    = &host_data->ncb_data;
+	if (np) PRINT_LUN(np, cmd->target, cmd->lun);
+}
+
+
+/*
+**	Host attach and initialisations.
+**
+**	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)
+
+{
+        struct host_data *host_data;
+	ncb_p np;
+        struct Scsi_Host *instance = 0;
+	u_long flags = 0;
+
+printf("ncr_attach: unit=%d chip=%d base=%x, io_port=%x, irq=%d\n", unit, chip, base, io_port, irq);
+
+	/*
+	**	Allocate host_data structure
+	*/
+        if (!(instance = scsi_register(tpnt, sizeof(*host_data))))
+	        goto attach_error;
+
+	/*
+	**	Initialize structure.
+	*/
+	instance->irq = irq;
+	host_data = (struct host_data *) instance->hostdata;
+
+	np        = &host_data->ncb_data;
+	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;
+
+	/*
+	**    Initialize timer structure
+        **
+        */
+	init_timer(&np->timer);
+	np->timer.data     = (unsigned long) np;
+	np->timer.function = ncr53c8xx_timeout;
+
+	/*
+	**	Try to map the controller chip to
+	**	virtual and physical memory.
+	*/
+
+	np->paddr = base;
+	np->vaddr = base;
+
+#ifndef NCR_IOMAPPED
+	np->reg_remapped = (struct ncr_reg *) remap_pci_mem((u_long) base, (u_long) 128);
+	if (!np->reg_remapped) {
+		printf("%s: can't map memory mapped IO region\n", ncr_name(np));
+		np->use_mmio = 0;
+	}
+	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
+	/*
+	**	Try to map the controller chip into iospace.
+	*/
+
+	request_region(io_port, 128, "ncr53c8xx");
+	np->port = io_port;
+
+	/*
+	**	Do chip dependent initialization.
+	*/
+
+	switch (device_id) {
+	case PCI_DEVICE_ID_NCR_53C825:
+	case PCI_DEVICE_ID_NCR_53C875:
+		np->maxwide = 1;
+		break;
+	default:
+		np->maxwide = 0;
+		break;
+	}
+
+	/*
+	**	Fill Linux host instance structure
+	*/
+#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
+	instance->max_channel	= 0;
+	instance->max_id	= np->maxwide ? 16 : 8;
+	instance->max_lun	= SCSI_NCR_MAX_LUN;
+#endif
+#ifndef NCR_IOMAPPED
+	instance->base		= (char *) np->reg_remapped;
+#endif
+	instance->io_port	= io_port;
+	instance->n_io_port	= 128;
+	instance->dma_channel	= 0;
+
+	/*
+	**	Patch script to physical addresses
+	*/
+	ncr_script_fill (&script0);
+	ncr_script_copy_and_bind (&script0, np);
+	np->ccb.p_ccb		= vtophys (&np->ccb);
+
+	/*
+	**	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->reg = (struct ncr_reg*) np->vaddr;
+
+#ifndef NCR_IOMAPPED
+retry_chip_init:
+#endif
+
+	/*
+	**  Get SCSI addr of host adapter (set by bios?).
+	*/
+
+	np->myaddr = INB(nc_scid) & 0x07;
+	if (!np->myaddr) np->myaddr = SCSI_NCR_MYADDR;
+
+	/*
+	**	Get the value of the chip's clock.
+	**	Find the right value for scntl3.
+	*/
+
+	ncr_getclock (np);
+
+	/*
+	**	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   );
+
+	/*
+	**	Now check the cache handling of the pci chipset.
+	*/
+
+	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;
+	};
+
+	/*
+	**	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_SHIRQ, "53c8xx", np)) {
+#   else
+	if (request_irq(irq, ncr53c8xx_intr, SA_INTERRUPT, "53c8xx", NULL)) {
+#   endif
+#else
+	if (request_irq(irq, ncr53c8xx_intr, SA_INTERRUPT, "53c8xx")) {
+#endif
+		printf("%s: request irq %d failure\n", ncr_name(np), irq);
+		goto attach_error;
+	}
+	np->irq = 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_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.
+	*/
+#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
+
+	/*
+	**	Now let the generic SCSI driver
+	**	look for the SCSI devices on the bus ..
+	*/
+
+	/*
+	**	start the timeout daemon
+	*/
+	ncr_timeout (np);
+	np->lasttime=0;
+
+	/*
+	**  use SIMPLE TAG messages by default
+	*/
+#ifdef SCSI_NCR_ALWAYS_SIMPLE_TAG
+	np->order = M_SIMPLE_TAG;
+#endif
+
+	/*
+	**  Done.
+	*/
+        if (!the_template) {
+        	the_template = instance->hostt;
+        	first_host = instance;
+	}
+
+	return 0;
+
+attach_error:
+	if (!instance) return -1;
+#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);
+	}
+#endif
+	if (np->port) {
+		printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
+		release_region(np->port, 128);
+	}
+	scsi_unregister(instance);
+
+        return -1;
+ }
+
+/*==========================================================
+**
+**
+**	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.
+**
+**
+**==========================================================
+*/
+int ncr_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
+{
+        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;
+	tcb_p tp                      = &np->target[cmd->target];
+
+	ccb_p cp;
+	lcb_p lp;
+
+	int	segments;
+	u_char	qidx, nego, idmsg, *msgptr;
+	u_long  msglen, msglen2;
+	u_long	flags;
+	int	xfer_direction;
+
+	cmd->scsi_done     = done;
+	cmd->host_scribble = NULL;
+	cmd->SCp.ptr       = NULL;
+	cmd->SCp.buffer    = NULL;
+
+	/*---------------------------------------------
+	**
+	**   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 ...
+	**
+	**---------------------------------------------
+	*/
+	if ((cmd->target == np->myaddr	  ) ||
+		(cmd->target >= MAX_TARGET) ||
+		(cmd->lun    >= MAX_LUN   )) {
+		return(DID_BAD_TARGET);
+        }
+
+
+	if (DEBUG_FLAGS & DEBUG_TINY) {
+		PRINT_ADDR(cmd);
+		printf ("CMD=%x ", cmd->cmnd[0]);
+	}
+
+	/*---------------------------------------------------
+	**
+	**	Assign a ccb / bind cmd
+	**	If no free ccb, insert cmd into the waiting list.
+	**
+	**----------------------------------------------------
+	*/
+	save_flags(flags); cli();
+
+        if (!(cp=ncr_get_ccb (np, cmd->target, cmd->lun))) {
+		insert_into_waiting_list(np, cmd);
+		restore_flags(flags);
+		return(DID_OK);
+	}
+	cp->cmd = cmd;
+
+	/*---------------------------------------------------
+	**
+	**	Enable tagged queue if asked by user
+	**
+	**----------------------------------------------------
+	*/
+#ifdef SCSI_NCR_TAGGED_QUEUE_DISABLED
+ 	if (cmd->device && cmd->device->tagged_queue &&
+	    (lp = tp->lp[cmd->lun]) && (!lp->usetags)) {
+		ncr_setmaxtags (np, tp, SCSI_NCR_MAX_TAGS);
+	}
+#endif
+
+	/*---------------------------------------------------
+	**
+	**	timestamp
+	**
+	**----------------------------------------------------
+	*/
+
+	bzero (&cp->phys.header.stamp, sizeof (struct tstamp));
+	cp->phys.header.stamp.start = jiffies;
+
+	/*----------------------------------------------------
+	**
+	**	Get device quirks from a speciality table.
+	**
+	**	@GENSCSI@
+	**	This should be a part of the device table
+	**	in "scsi_conf.c".
+	**
+	**----------------------------------------------------
+	*/
+	if (tp->quirks & QUIRK_UPDATE) {
+		tp->quirks = ncr_lookup ((char*) &tp->inqdata[0]);
+#ifndef NCR_GETCC_WITHMSG
+		if (tp->quirks) {
+			PRINT_ADDR(cmd);
+			printf ("quirks=%x.\n", tp->quirks);
+		}
+#endif
+	}
+
+	/*---------------------------------------------------
+	**
+	**	negotiation required?
+	**
+	**	Only SCSI-II devices.
+	**	To negotiate with SCSI-I devices is dangerous, since
+	**	Synchronous Negotiation protocol is optional, and
+	**	INQUIRY data do not contains capabilities in byte 7.
+	**----------------------------------------------------
+	*/
+
+	nego = 0;
+
+	if (cmd->lun == 0 && (tp->inqdata[2] & 0x7) >= 2 && tp->inqdata[7]) {
+		/*
+		**	negotiate wide transfers ?
+		*/
+
+		if (!tp->widedone) {
+			if (tp->inqdata[7] & INQ7_WIDE16) {
+				nego = NS_WIDE;
+			} else
+				tp->widedone=1;
+		};
+
+		/*
+		**	negotiate synchronous transfers?
+		*/
+
+		if (!nego && !tp->period) {
+			if (SCSI_NCR_MAX_SYNC 
+#if defined (CDROM_ASYNC)
+			    && ((tp->inqdata[0] & 0x1f) != 5)
+#endif
+			    && (tp->inqdata[7] & INQ7_SYNC)) {
+				nego = NS_SYNC;
+			} else {
+				tp->period  =0xffff;
+				tp->sval = 0xe0;
+				PRINT_ADDR(cmd);
+				printf ("asynchronous.\n");
+			};
+		};
+	};
+
+	/*---------------------------------------------------
+	**
+	**	choose a new tag ...
+	**
+	**----------------------------------------------------
+	*/
+
+	if ((lp = tp->lp[cmd->lun]) && (lp->usetags)) {
+		/*
+		**	assign a tag to this ccb!
+		*/
+		while (!cp->tag) {
+			ccb_p cp2 = lp->next_ccb;
+			lp->lasttag = lp->lasttag % 255 + 1;
+			while (cp2 && cp2->tag != lp->lasttag)
+				cp2 = cp2->next_ccb;
+			if (cp2) continue;
+			cp->tag=lp->lasttag;
+			if (DEBUG_FLAGS & DEBUG_TAGS) {
+				PRINT_ADDR(cmd);
+				printf ("using tag #%d.\n", cp->tag);
+			}
+		}
+	} else {
+		cp->tag=0;
+	}
+
+	/*----------------------------------------------------
+	**
+	**	Build the identify / tag / sdtr message
+	**
+	**----------------------------------------------------
+	*/
+
+	idmsg = M_IDENTIFY | cmd->lun;
+
+	if ((cp!=&np->ccb) && (np->disc))
+		idmsg |= 0x40;
+
+	msgptr = cp->scsi_smsg;
+	msglen = 0;
+	msgptr[msglen++] = idmsg;
+
+	if (cp->tag) {
+	    char tag;
+
+	    tag = np->order;
+	    if (tag == 0) {
+		/*
+		**	Ordered write ops, unordered read ops.
+		*/
+		switch (cmd->cmnd[0]) {
+		case 0x08:  /* READ_SMALL (6) */
+		case 0x28:  /* READ_BIG  (10) */
+		case 0xa8:  /* READ_HUGE (12) */
+		    tag = M_SIMPLE_TAG;
+		    break;
+		default:
+		    tag = M_ORDERED_TAG;
+		}
+	    }
+	    /*
+	    **	Have to force ordered tag to avoid timeouts
+	    */
+	    if ((lp = tp->lp[cmd->lun]) && (lp->force_ordered_tag)) {
+		tag = M_ORDERED_TAG;
+		lp->force_ordered_tag = 0;
+		if (DEBUG_FLAGS & DEBUG_TAGS) {
+			PRINT_ADDR(cmd);
+			printf ("Ordered Queue Tag forced\n");
+		}
+	    }
+	    msgptr[msglen++] = tag;
+	    msgptr[msglen++] = cp -> tag;
+	}
+
+	switch (nego) {
+	case NS_SYNC:
+		msgptr[msglen++] = M_EXTENDED;
+		msgptr[msglen++] = 3;
+		msgptr[msglen++] = M_X_SYNC_REQ;
+		msgptr[msglen++] = tp->maxoffs ? tp->minsync : 0;
+		msgptr[msglen++] = tp->maxoffs;
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			PRINT_ADDR(cp->cmd);
+			printf ("sync msgout: ");
+			ncr_show_msg (&cp->scsi_smsg [msglen-5]);
+			printf (".\n");
+		};
+		break;
+	case NS_WIDE:
+		msgptr[msglen++] = M_EXTENDED;
+		msgptr[msglen++] = 2;
+		msgptr[msglen++] = M_X_WIDE_REQ;
+		msgptr[msglen++] = tp->usrwide;
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			PRINT_ADDR(cp->cmd);
+			printf ("wide msgout: ");
+			ncr_show_msg (&cp->scsi_smsg [msglen-4]);
+			printf (".\n");
+		};
+		break;
+	};
+
+	/*----------------------------------------------------
+	**
+	**	Build the identify message for getcc.
+	**
+	**----------------------------------------------------
+	*/
+
+	cp -> scsi_smsg2 [0] = idmsg;
+	msglen2 = 1;
+
+	/*----------------------------------------------------
+	**
+	**	Build the data descriptors
+	**
+	**----------------------------------------------------
+	*/
+
+	segments = ncr_scatter (cp, cp->cmd);
+
+	if (segments < 0) {
+		ncr_free_ccb(np, cp);
+		restore_flags(flags);
+		return(DID_ERROR);
+	}
+
+	/*----------------------------------------------------
+	**
+	**	Guess xfer direction.
+	**	Spare some CPU by testing here frequently opcode.
+	**
+	**----------------------------------------------------
+	*/
+	switch((int) cmd->cmnd[0]) {
+	case 0x08:  /*	READ(6)				08 */
+	case 0x28:  /*	READ(10)			28 */
+		xfer_direction = XferIn;
+		break;
+	case 0x0A:  /*	WRITE(6)			0A */
+	case 0x2A:  /*	WRITE(10)			2A */
+		xfer_direction = XferOut;
+		break;
+	default:
+		xfer_direction = guess_xfer_direction((int) cmd->cmnd[0]);
+		break;
+	}
+
+	/*----------------------------------------------------
+	**
+	**	Set the SAVED_POINTER.
+	**
+	**----------------------------------------------------
+	*/
+
+	switch (xfer_direction) {
+	default:
+	case XferIn:
+	     cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_in);
+	     cp->phys.header.goalp = cp->phys.header.savep +20 +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;
+	case XferNone:
+	     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;
+
+	/*----------------------------------------------------
+	**
+	**	fill in ccb
+	**
+	**----------------------------------------------------
+	**
+	**
+	**	physical -> virtual backlink
+	**	Generic SCSI command
+	*/
+	cp->phys.header.cp		= cp;
+	/*
+	**	Startqueue
+	*/
+	cp->phys.header.launch.l_paddr	= NCB_SCRIPT_PHYS (np, select);
+	cp->phys.header.launch.l_cmd	= SCR_JUMP;
+	/*
+	**	select
+	*/
+	cp->phys.select.sel_id		= cmd->target;
+	cp->phys.select.sel_scntl3	= tp->wval;
+	cp->phys.select.sel_sxfer	= tp->sval;
+	/*
+	**	message
+	*/
+	cp->phys.smsg.addr		= CCB_PHYS (cp, scsi_smsg);
+	cp->phys.smsg.size		= msglen;
+
+	cp->phys.smsg2.addr		= CCB_PHYS (cp, scsi_smsg2);
+	cp->phys.smsg2.size		= msglen2;
+	/*
+	**	command
+	*/
+	cp->phys.cmd.addr		= vtophys (&cmd->cmnd[0]);
+	cp->phys.cmd.size		= cmd->cmd_len;
+	/*
+	**	sense command
+	*/
+	cp->phys.scmd.addr		= CCB_PHYS (cp, sensecmd);
+	cp->phys.scmd.size		= 6;
+	/*
+	**	patch requested size into sense command
+	*/
+	cp->sensecmd[0]			= 0x03;
+	cp->sensecmd[1]			= cmd->lun << 5;
+	cp->sensecmd[4]			= sizeof(cmd->sense_buffer);
+	/*
+	**	sense data
+	*/
+	cp->phys.sense.addr		= vtophys (&cmd->sense_buffer[0]);
+	cp->phys.sense.size		= sizeof(cmd->sense_buffer);
+	/*
+	**	status
+	*/
+	cp->actualquirks		= tp->quirks;
+	cp->host_status			= nego ? HS_NEGOTIATE : HS_BUSY;
+	cp->scsi_status			= S_ILLEGAL;
+	cp->parity_status		= 0;
+
+	cp->xerr_status			= XE_OK;
+	cp->sync_status			= tp->sval;
+	cp->nego_status			= nego;
+	cp->wide_status			= tp->wval;
+
+	/*----------------------------------------------------
+	**
+	**	Critical region: start this job.
+	**
+	**----------------------------------------------------
+	*/
+
+	/*
+	**	reselect pattern and activate this job.
+	*/
+
+	cp->jump_ccb.l_cmd	= (SCR_JUMP ^ IFFALSE (DATA (cp->tag)));
+	/* Compute a time limit bigger than the middle-level driver one */
+	if (cmd->timeout_per_command > 0)
+		cp->tlimit	= jiffies + cmd->timeout_per_command + NCR_TIMEOUT_INCREASE;
+	else
+		cp->tlimit	= jiffies + 3600 * HZ; /* No timeout=one hour */
+	cp->magic		= CCB_MAGIC;
+
+	/*
+	**	insert into start queue.
+	*/
+
+	qidx = np->squeueput + 1;
+	if (qidx >= MAX_START) qidx=0;
+	np->squeue [qidx	 ] = NCB_SCRIPT_PHYS (np, idle);
+	np->squeue [np->squeueput] = CCB_PHYS (cp, phys);
+	np->squeueput = qidx;
+
+	if(DEBUG_FLAGS & DEBUG_QUEUE)
+		printf ("%s: queuepos=%d tryoffset=%d.\n", ncr_name (np),
+		np->squeueput,
+		(unsigned)(np->script->startpos[0]- 
+			   (NCB_SCRIPT_PHYS (np, tryloop))));
+
+	/*
+	**	Script processor may be waiting for reselect.
+	**	Wake it up.
+	*/
+	OUTB (nc_istat, SIGP);
+
+	/*
+	**	and reenable interrupts
+	*/
+	restore_flags(flags);
+
+	/*
+	**	Command is successfully queued.
+	*/
+
+	return(DID_OK);
+}
+
+/*==========================================================
+**
+**
+**	Reset the SCSI BUS.
+**	This is called from the generic SCSI driver.
+**
+**
+**==========================================================
+*/
+int ncr_reset_bus (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;
+	u_long flags;
+
+	save_flags(flags); cli();
+
+	reset_waiting_list(np);
+	ncr_init(np, "scsi bus reset", HS_RESET);
+
+#ifndef SCSI_NCR_NO_DISCONNECT
+	np->disc = 1;
+#endif
+
+	restore_flags(flags);
+
+	return SCSI_RESET_SUCCESS;
+}
+
+/*==========================================================
+**
+**
+**	Abort an SCSI command.
+**	This is called from the generic SCSI driver.
+**
+**
+**==========================================================
+*/
+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;
+	ccb_p cp;
+	u_long flags;
+	int found;
+	int retv;
+
+	save_flags(flags); cli();
+/*
+ * First, look for the scsi command in the waiting list
+ */
+	if (remove_from_waiting_list(np, cmd)) {
+		cmd->result = ScsiResult(DID_ABORT, 0);
+		cmd->scsi_done(cmd);
+		restore_flags(flags);
+		return SCSI_ABORT_SUCCESS;
+	}
+
+/*
+ * Then, 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;
+		}
+	}
+	if (!found) {
+		restore_flags(flags);
+		return SCSI_ABORT_NOT_RUNNING;
+	}
+
+	/*
+	**	Disable reselect.
+	**      Remove it from startqueue.
+	*/
+	cp->jump_ccb.l_cmd = (SCR_JUMP);
+	if (cp->phys.header.launch.l_paddr == NCB_SCRIPT_PHYS (np, select)) {
+		printf ("%s: abort ccb=%p (skip)\n", ncr_name (np), cp);
+		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;
+	}
+
+	restore_flags(flags);
+
+	return retv;
+}
+
+/*==========================================================
+**
+**	Linux release module stuff.
+**
+**	Called before unloading the module
+**	Detach the host.
+**	We have to free resources and halt the NCR chip
+**
+**==========================================================
+*/
+
+#ifdef MODULE
+static int ncr_detach(ncb_p np, int irq)
+{
+	ccb_p cp;
+	tcb_p tp;
+	lcb_p lp;
+	int target, lun;
+	int i;
+
+	printf("%s: releasing host resources\n", ncr_name(np));
+
+/*
+**	Stop the ncr_timeout process
+**	Set release_stage to 1 and wait that ncr_timeout() set it to 2.
+*/
+
+#ifdef DEBUG
+	printf("%s: stopping the timer\n", ncr_name(np));
+#endif
+	np->release_stage = 1;
+	for (i = 50 ; i && np->release_stage != 2 ; i--) DELAY(100000);
+	if (np->release_stage != 2)
+		printf("%s: the timer seems to be already stopped\n", ncr_name(np));
+	else np->release_stage = 2;
+
+/*
+**	Disable chip interrupts
+*/
+
+#ifdef DEBUG
+	printf("%s: disabling chip interrupts\n", ncr_name(np));
+#endif
+	OUTW (nc_sien , 0);
+	OUTB (nc_dien , 0);
+
+/*
+**	Free irq
+*/
+
+#ifdef DEBUG
+	printf("%s: freeing irq %d\n", ncr_name(np), irq);
+#endif
+#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
+#   ifdef SCSI_NCR_SHARE_IRQ
+	free_irq(irq, np);
+#   else
+	free_irq(irq, NULL);
+#   endif
+#else
+	free_irq(irq);
+#endif
+
+	/*
+	**	Reset NCR chip
+	*/
+
+	printf("%s: resetting chip\n", ncr_name(np));
+	OUTB (nc_istat,  SRST);
+	DELAY (1000);
+	OUTB (nc_istat,  0   );
+
+	/*
+	**	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);
+#endif
+	unmap_pci_mem((vm_offset_t) np->reg_remapped, (u_long) 128);
+#endif
+
+#ifdef DEBUG
+	printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
+#endif
+	release_region(np->port, 128);
+
+	/*
+	**	Free allocated ccb(s)
+	*/
+
+	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
+	printf("%s: freeing ccb (%lx)\n", ncr_name(np), (u_long) cp);
+#endif
+		m_free(cp, sizeof(*cp));
+	}
+
+	/*
+	**	Free allocated tp(s)
+	*/
+
+	for (target = 0; target < MAX_TARGET ; target++) {
+		tp=&np->target[target];
+		for (lun = 0 ; lun < MAX_LUN ; lun++) {
+			lp = tp->lp[lun];
+			if (lp) {
+#ifdef DEBUG
+	printf("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp);
+#endif
+				m_free(lp, sizeof(*lp));
+			}
+		}
+	}
+
+	printf("%s: host resources successfully released\n", ncr_name(np));
+
+	return 1;
+}
+#endif
+
+/*==========================================================
+**
+**
+**	Complete execution of a SCSI command.
+**	Signal completion to the generic SCSI driver.
+**
+**
+**==========================================================
+*/
+
+void ncr_complete (ncb_p np, ccb_p cp)
+{
+	Scsi_Cmnd *cmd;
+	tcb_p tp;
+	lcb_p lp;
+
+	/*
+	**	Sanity check
+	*/
+
+	if (!cp || (cp->magic!=CCB_MAGIC) || !cp->cmd) return;
+	cp->magic = 1;
+	cp->tlimit= 0;
+	cmd = cp->cmd;
+
+	/*
+	**	No Reselect anymore.
+	*/
+	cp->jump_ccb.l_cmd = (SCR_JUMP);
+
+	/*
+	**	No starting.
+	*/
+	cp->phys.header.launch.l_paddr= NCB_SCRIPT_PHYS (np, idle);
+
+	/*
+	**	timestamp
+	**	Optional, spare some CPU time
+	*/
+#ifdef SCSI_NCR_PROFILE
+	ncb_profile (np, cp);
+#endif
+
+	if (DEBUG_FLAGS & DEBUG_TINY)
+		printf ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp & 0xfff,
+			cp->host_status,cp->scsi_status);
+
+	cmd = cp->cmd;
+	cp->cmd = NULL;
+	tp = &np->target[cmd->target];
+
+	/*
+	**	Check for parity errors.
+	*/
+
+	if (cp->parity_status) {
+		PRINT_ADDR(cmd);
+		printf ("%d parity error(s), fallback.\n", cp->parity_status);
+		/*
+		**	fallback to asynch transfer.
+		*/
+		tp->usrsync=255;
+		tp->period =  0;
+	}
+
+	/*
+	**	Check for extended errors.
+	*/
+
+	if (cp->xerr_status != XE_OK) {
+		PRINT_ADDR(cmd);
+		switch (cp->xerr_status) {
+		case XE_EXTRA_DATA:
+			printf ("extraneous data discarded.\n");
+			break;
+		case XE_BAD_PHASE:
+			printf ("illegal scsi phase (4/5).\n");
+			break;
+		default:
+			printf ("extended error %d.\n", cp->xerr_status);
+			break;
+		}
+		if (cp->host_status==HS_COMPLETE)
+			cp->host_status = HS_FAIL;
+	}
+
+	/*
+	**	Check the status.
+	*/
+	if (   (cp->host_status == HS_COMPLETE)
+		&& (cp->scsi_status == S_GOOD)) {
+
+		/*
+		**	All went well.
+		*/
+		cmd->result = ScsiResult(DID_OK, cp->scsi_status);
+
+		/*
+		** if (cp->phys.header.lastp != cp->phys.header.goalp)...
+		**
+		**	@RESID@
+		**	Could dig out the correct value for resid,
+		**	but it would be quite complicated.
+		**
+		**	The ah1542.c driver sets it to 0 too ...
+		*/
+
+		/*
+		**	Try to assign a ccb to this nexus
+		*/
+		ncr_alloc_ccb (np, cmd->target, cmd->lun);
+
+		/*
+		**	On inquire cmd (0x12) save some data.
+		**	Clear questionnable capacities.
+		*/
+		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]);
+			}
+			bcopy (	cmd->request_buffer,
+				&tp->inqdata,
+				sizeof (tp->inqdata));
+
+			/*
+			**	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
+			/*
+			**	prepare negotiation of synch and wide.
+			*/
+			ncr_negotiate (np, tp);
+
+			/*
+			**	force quirks update before next command start
+			*/
+			tp->quirks |= QUIRK_UPDATE;
+		}
+
+		tp->bytes     += cp->data_len;
+		tp->transfers ++;
+	} else if ((cp->host_status == HS_COMPLETE)
+		&& (cp->scsi_status == (S_SENSE|S_GOOD) ||
+		    cp->scsi_status == (S_SENSE|S_CHECK_COND))) {
+
+		/*
+		**   Check condition code
+		*/
+		cmd->result = ScsiResult(DID_OK, S_CHECK_COND);
+
+		if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
+			u_char * p = (u_char*) & cmd->sense_buffer;
+			int i;
+			printf ("\n%s: sense data:", ncr_name (np));
+			for (i=0; i<14; i++) printf (" %x", *p++);
+			printf (".\n");
+		}
+
+	} else if ((cp->host_status == HS_COMPLETE)
+		&& (cp->scsi_status == S_BUSY)) {
+
+		/*
+		**   Target is busy.
+		*/
+		cmd->result = ScsiResult(DID_OK, cp->scsi_status);
+
+	} else if ((cp->host_status == HS_SEL_TIMEOUT)
+		|| (cp->host_status == HS_TIMEOUT)) {
+
+		/*
+		**   No response
+		*/
+		cmd->result = ScsiResult(DID_TIME_OUT, cp->scsi_status);
+
+	} else if (cp->host_status == HS_RESET) {
+
+		/*
+		**   SCSI bus reset
+		*/
+		cmd->result = ScsiResult(DID_RESET, cp->scsi_status);
+
+	} else if (cp->host_status == HS_ABORTED) {
+
+		/*
+		**   Transfer aborted
+		*/
+		cmd->result = ScsiResult(DID_ABORT, cp->scsi_status);
+
+	} else {
+
+		/*
+		**  Other protocol messes
+		*/
+		PRINT_ADDR(cmd);
+		printf ("COMMAND FAILED (%x %x) @%p.\n",
+			cp->host_status, cp->scsi_status, cp);
+
+		cmd->result = ScsiResult(DID_ERROR, cp->scsi_status);
+	}
+
+	/*
+	**	trace output
+	*/
+
+	if (tp->usrflag & UF_TRACE) {
+		u_char * p;
+		int i;
+		PRINT_ADDR(cmd);
+		printf (" CMD:");
+		p = (u_char*) &cmd->cmnd[0];
+		for (i=0; i<cmd->cmd_len; i++) printf (" %x", *p++);
+
+		if (cp->host_status==HS_COMPLETE) {
+			switch (cp->scsi_status) {
+			case S_GOOD:
+				printf ("  GOOD");
+				break;
+			case S_CHECK_COND:
+				printf ("  SENSE:");
+				p = (u_char*) &cmd->sense_buffer;
+				for (i=0; i<14; i++)
+					printf (" %x", *p++);
+				break;
+			default:
+				printf ("  STAT: %x\n", cp->scsi_status);
+				break;
+			}
+		} else printf ("  HOSTERROR: %x", cp->host_status);
+		printf ("\n");
+	}
+
+	/*
+	**	Free this ccb
+	*/
+	ncr_free_ccb (np, cp);
+
+	/*
+	**	requeue awaiting scsi commands
+	*/
+	if (np->waiting_list) requeue_waiting_list(np);
+
+	/*
+	**	signal completion to generic driver.
+	*/
+	cmd->scsi_done (cmd);
+}
+
+/*==========================================================
+**
+**
+**	Signal all (or one) control block done.
+**
+**
+**==========================================================
+*/
+
+void ncr_wakeup (ncb_p np, u_long code)
+{
+	/*
+	**	Starting at the default ccb and following
+	**	the links, complete all jobs with a
+	**	host_status greater than "disconnect".
+	**
+	**	If the "code" parameter is not zero,
+	**	complete all jobs that are not IDLE.
+	*/
+
+	ccb_p cp = &np->ccb;
+	while (cp) {
+		switch (cp->host_status) {
+
+		case HS_IDLE:
+			break;
+
+		case HS_DISCONNECT:
+			if(DEBUG_FLAGS & DEBUG_TINY) printf ("D");
+			/* fall through */
+
+		case HS_BUSY:
+		case HS_NEGOTIATE:
+			if (!code) break;
+			cp->host_status = code;
+
+			/* fall through */
+
+		default:
+			ncr_complete (np, cp);
+			break;
+		};
+		cp = cp -> link_ccb;
+	};
+}
+
+/*==========================================================
+**
+**
+**	Start NCR chip.
+**
+**
+**==========================================================
+*/
+
+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.
+	*/
+
+	OUTB (nc_istat,  SRST);
+	DELAY (10000);
+
+	/*
+	**	Message.
+	*/
+
+	if (msg) printf ("%s: restart (%s).\n", ncr_name (np), msg);
+
+	/*
+	**	Clear Start Queue
+	*/
+	for (i=0;i<MAX_START;i++)
+		np -> squeue [i] = NCB_SCRIPT_PHYS (np, idle);
+
+	/*
+	**	Start at first entry.
+	*/
+
+	np->squeueput = 0;
+	np->script->startpos[0] = NCB_SCRIPT_PHYS (np, tryloop);
+	np->script->start0  [0] = SCR_INT ^ IFFALSE (0);
+
+	/*
+	**	Wakeup all pending jobs.
+	*/
+	ncr_wakeup (np, code);
+
+	/*
+	**	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, 0x00);	/* Set 2-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 */
+		OUTB(nc_ctest5, 0x04);	/* Set DMA FIFO to 88 */
+#if 0
+		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
+
+	OUTB (nc_istat,  0      );      /*  Remove Reset, abort ...	     */
+
+#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*/
+
+#ifdef SCSI_NCR_DISABLE_MPARITY_CHECK
+	OUTB (nc_ctest4, 0x00	);	/*  disable master parity checking   */
+#else
+	OUTB (nc_ctest4, 0x08	);	/*  enable master parity checking    */
+#endif
+
+	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  */
+
+	/*
+	**	Reinitialize usrsync.
+	**	Have to renegotiate synch mode.
+	*/
+
+	usrsync = 255;
+
+#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
+
+	/*
+	**	Reinitialize usrwide.
+	**	Have to renegotiate wide mode.
+	*/
+
+	usrwide = (SCSI_NCR_MAX_WIDE);
+	if (usrwide > np->maxwide) usrwide=np->maxwide;
+
+	/*
+	**	Disable disconnects.
+	*/
+
+	np->disc = 0;
+
+	/*
+	**	Fill in target structure.
+	*/
+
+	for (i=0;i<MAX_TARGET;i++) {
+		tcb_p tp = &np->target[i];
+
+		tp->sval    = 0;
+		tp->wval    = np->rv_scntl3;
+
+		tp->usrsync = usrsync;
+		tp->usrwide = usrwide;
+
+		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.
+	*/
+
+	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
+}
+
+/*==========================================================
+**
+**	Prepare the negotiation values for wide and
+**	synchronous transfers.
+**
+**==========================================================
+*/
+
+static void ncr_negotiate (struct ncb* np, struct tcb* tp)
+{
+	/*
+	**	minsync unit is 4ns !
+	*/
+
+	u_long minsync = tp->usrsync;
+
+	if (minsync < 25) minsync=25;
+
+	/*
+	**	if not scsi 2
+	**	don't believe FAST!
+	*/
+
+	if ((minsync < 50) && (tp->inqdata[2] & 0x0f) < 2)
+		minsync=50;
+
+	/*
+	**	our limit ..
+	*/
+
+	if (minsync < np->ns_sync)
+		minsync = np->ns_sync;
+
+	/*
+	**	divider limit
+	*/
+
+	if (minsync > (np->ns_sync * 11) / 4)
+		minsync = 255;
+
+	tp->minsync = minsync;
+	tp->maxoffs = (minsync<255 ? 8 : 0);
+
+	/*
+	**	period=0: has to negotiate sync transfer
+	*/
+
+	tp->period=0;
+
+	/*
+	**	widedone=0: has to negotiate wide transfer
+	*/
+	tp->widedone=0;
+}
+
+/*==========================================================
+**
+**	Switch sync mode for current job and it's target
+**
+**==========================================================
+*/
+
+static void ncr_setsync (ncb_p np, ccb_p cp, u_char sxfer)
+{
+	Scsi_Cmnd *cmd;
+	tcb_p tp;
+	u_char target = INB (nc_ctest0)&7;
+
+	assert (cp);
+	if (!cp) return;
+
+	cmd = cp->cmd;
+	assert (cmd);
+	if (!cmd) return;
+	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;
+	tp->sval = sxfer;
+
+	/*
+	**	Bells and whistles   ;-)
+	*/
+	PRINT_ADDR(cmd);
+	if (sxfer & 0x0f) {
+		/*
+		**  Disable extended Sreq/Sack filtering
+		*/
+		if (tp->period <= 200) OUTB (nc_stest2, 0);
+
+		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");
+
+	/*
+	**	set actual value and sync_status
+	*/
+	OUTB (nc_sxfer, sxfer);
+	np->sync_st = sxfer;
+
+	/*
+	**	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;
+	};
+}
+
+/*==========================================================
+**
+**	Switch wide mode for current job and it's target
+**
+**==========================================================
+*/
+
+static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide)
+{
+	Scsi_Cmnd *cmd;
+	u_short target = INB (nc_ctest0)&7;
+	tcb_p tp;
+	u_char	scntl3 = np->rv_scntl3 | (wide ? EWS : 0);
+
+	assert (cp);
+	if (!cp) return;
+
+	cmd = cp->cmd;
+	assert (cmd);
+	if (!cmd) return;
+	assert (target == (cmd->target & 0xf));
+
+	tp = &np->target[target];
+	tp->widedone  =  wide+1;
+	if (tp->wval == scntl3) return;
+	tp->wval = scntl3;
+
+	/*
+	**	Bells and whistles   ;-)
+	*/
+	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
+	*/
+	OUTB (nc_scntl3, scntl3);
+	np->wide_st = scntl3;
+
+	/*
+	**	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;
+	};
+}
+
+/*==========================================================
+**
+**	Switch tagged mode for a target.
+**
+**==========================================================
+*/
+
+static void ncr_setmaxtags (ncb_p np, tcb_p tp, u_long usrtags)
+{
+	int l;
+	tp->usrtags = usrtags;
+	for (l=0; l<MAX_LUN; l++) {
+		lcb_p lp;
+		if (!tp) break;
+		lp=tp->lp[l];
+		if (!lp) continue;
+		ncr_settags (tp, lp);
+		if (lp->usetags > 0) {
+			PRINT_LUN(np, tp - np->target, l);
+			printf("using tagged command queueing, up to %d cmds/lun\n", lp->usetags);
+		}
+	};
+}
+
+static void ncr_settags (tcb_p tp, lcb_p lp)
+{
+	u_char reqtags, tmp;
+
+	if ((!tp) || (!lp)) return;
+
+	/*
+	**	only devices conformant to ANSI Version >= 2
+	**	only devices capable of tagges commands
+	**	only disk devices
+	**	only if enabled by user ..
+	*/
+	if ((  tp->inqdata[2] & 0x7) >= 2 &&
+	    (  tp->inqdata[7] & INQ7_QUEUE) && ((tp->inqdata[0] & 0x1f)==0x00)
+		&& tp->usrtags) {
+		reqtags = tp->usrtags;
+		if (lp->actlink <= 1)
+			lp->usetags=reqtags;
+	} else {
+		reqtags = 1;
+		if (lp->actlink <= 1)
+			lp->usetags=0;
+	};
+
+	/*
+	**	don't announce more than available.
+	*/
+	tmp = lp->actccbs;
+	if (tmp > reqtags) tmp = reqtags;
+	lp->reqlink = tmp;
+
+	/*
+	**	don't discard if announced.
+	*/
+	tmp = lp->actlink;
+	if (tmp < reqtags) tmp = reqtags;
+	lp->reqccbs = tmp;
+}
+
+/*----------------------------------------------------
+**
+**	handle user commands
+**
+**----------------------------------------------------
+*/
+
+#ifdef SCSI_NCR_USER_COMMAND
+
+static void ncr_usercmd (ncb_p np)
+{
+	u_char t;
+	tcb_p tp;
+
+	switch (np->user.cmd) {
+
+	case 0: return;
+
+	case UC_SETSYNC:
+		for (t=0; t<MAX_TARGET; t++) {
+			if (!((np->user.target>>t)&1)) continue;
+			tp = &np->target[t];
+			tp->usrsync = np->user.data;
+			ncr_negotiate (np, tp);
+		};
+		break;
+
+	case UC_SETTAGS:
+		if (np->user.data > SCSI_NCR_MAX_TAGS)
+			np->user.data = SCSI_NCR_MAX_TAGS;
+		for (t=0; t<MAX_TARGET; t++) {
+			if (!((np->user.target>>t)&1)) continue;
+			ncr_setmaxtags (np, &np->target[t], np->user.data);
+		};
+		np->disc = 1;
+		break;
+
+	case UC_SETDEBUG:
+#ifdef SCSI_NCR_DEBUG
+		ncr_debug = np->user.data;
+#endif
+		break;
+
+	case UC_SETORDER:
+		np->order = np->user.data;
+		break;
+
+	case UC_SETWIDE:
+		for (t=0; t<MAX_TARGET; t++) {
+			u_long size;
+			if (!((np->user.target>>t)&1)) continue;
+			tp = &np->target[t];
+			size = np->user.data;
+			if (size > np->maxwide) size=np->maxwide;
+			tp->usrwide = size;
+			ncr_negotiate (np, tp);
+		};
+		break;
+
+	case UC_SETFLAG:
+		for (t=0; t<MAX_TARGET; t++) {
+			if (!((np->user.target>>t)&1)) continue;
+			tp = &np->target[t];
+			tp->usrflag = np->user.data;
+		};
+		break;
+
+	case UC_CLEARPROF:
+		bzero(&np->profile, sizeof(np->profile));
+		break;
+	}
+	np->user.cmd=0;
+}
+#endif
+
+
+
+/*==========================================================
+**
+**
+**	ncr timeout handler.
+**
+**
+**==========================================================
+**
+**	Misused to keep the driver running when
+**	interrupts are not configured correctly.
+**
+**----------------------------------------------------------
+*/
+
+static void ncr_timeout (ncb_p np)
+{
+	u_long	thistime = jiffies;
+	u_long	count = 0;
+	long signed   t;
+	ccb_p cp;
+	u_long flags;
+
+	/*
+	**	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;
+		return;
+	}
+
+	np->timer.expires =
+#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
+			jiffies +
+#endif
+			SCSI_NCR_TIMER_INTERVAL;
+
+	add_timer(&np->timer);
+
+	if (np->lasttime + HZ < thistime) {
+		/*
+		**	block ncr interrupts
+		*/
+		save_flags(flags); cli();
+
+		np->lasttime = thistime;
+
+		/*
+		**	Reset profile data to avoid ugly overflow
+		**	(Limited to 1024 GB for 32 bit architecture)
+		*/
+		if (np->profile.num_kbytes > (~0UL >> 2))
+			bzero(&np->profile, sizeof(np->profile));
+
+		/*----------------------------------------------------
+		**
+		**	handle ncr chip timeouts
+		**
+		**	Assumption:
+		**	We have a chance to arbitrate for the
+		**	SCSI bus at least every 10 seconds.
+		**
+		**----------------------------------------------------
+		*/
+
+		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.
+		**----------------------------------------------------
+		*/
+
+		for (cp=&np->ccb; cp; cp=cp->link_ccb) {
+			/*
+			**	look for timed out ccbs.
+			*/
+			if (!cp->host_status) continue;
+			count++;
+			/*
+			**	Have to force ordered tag to avoid timeouts
+			*/
+			if (cp->cmd && cp->tlimit <= 
+				thistime + NCR_TIMEOUT_INCREASE + SCSI_NCR_TIMEOUT_ALERT) {
+				lcb_p lp;
+				lp = np->target[cp->cmd->target].lp[cp->cmd->lun];
+				if (lp && !lp->force_ordered_tag) {
+					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.
+			*/
+			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);
+			};
+
+			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))
+					continue;
+
+				/* fall through */
+			case HS_DISCONNECT:
+				cp->host_status=HS_TIMEOUT;
+			};
+			cp->tag = 0;
+
+			/*
+			**	wakeup this ccb.
+			*/
+			ncr_complete (np, cp);
+#endif
+		}
+		restore_flags(flags);
+	}
+
+#ifdef SCSI_NCR_BROKEN_INTR
+	if (INB(nc_istat) & (INTF|SIP|DIP)) {
+
+		/*
+		**	Process pending interrupts.
+		*/
+		save_flags(flags); cli();
+		if (DEBUG_FLAGS & DEBUG_TINY) printf ("{");
+		ncr_exception (np);
+		if (DEBUG_FLAGS & DEBUG_TINY) printf ("}");
+		restore_flags(flags);
+	}
+#endif /* SCSI_NCR_BROKEN_INTR */
+}
+
+/*==========================================================
+**
+**
+**	ncr chip exception handler.
+**
+**
+**==========================================================
+*/
+
+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");
+		OUTB (nc_istat, (istat & SIGP) | INTF);
+		np->profile.num_fly++;
+		ncr_wakeup (np, 0);
+	};
+
+	if (!(istat & (SIP|DIP))) return;
+
+	/*
+	**	Steinbach's Guideline for Systems Programming:
+	**	Never test for an error condition you don't know how to handle.
+	*/
+
+	dstat = INB (nc_dstat);
+	sist  = INW (nc_sist) ;
+	np->profile.num_int++;
+
+	if (DEBUG_FLAGS & DEBUG_TINY)
+		printf ("<%d|%x:%x|%x:%x>",
+			(int)INB(nc_scr0),
+			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
+	**
+	**	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);
+		return;
+	};
+
+	/*----------------------------------------
+	**	move command with length 0
+	**----------------------------------------
+	*/
+
+	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));
+		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);
+		return;
+	};
+
+	/*========================================
+	**	do the register dump
+	**========================================
+	*/
+	if (jiffies - np->regtime > 10*HZ) {
+		int i;
+		np->regtime = jiffies;
+		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  */
+	}
+
+	/*----------------------------------------
+	**	handshake timeout
+	**----------------------------------------
+	*/
+
+	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));
+		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;
+		};
+		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);
+		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 ...
+	*/
+
+	ncr_init (np, "fatal error", HS_FAIL);
+#ifndef SCSI_NCR_NO_DISCONNECT
+	np->disc = 1;
+#endif
+}
+
+/*==========================================================
+**
+**	ncr chip exception handler for selection timeout
+**
+**==========================================================
+**
+**	There seems to be a bug in the 53c810.
+**	Although a STO-Interrupt is pending,
+**	it continues executing script commands.
+**	But it will fail and interrupt (IID) on
+**	the next instruction where it's looking
+**	for a valid phase.
+**
+**----------------------------------------------------------
+*/
+
+void ncr_int_sto (ncb_p np)
+{
+	u_long dsa, scratcha, diff;
+	ccb_p cp;
+	if (DEBUG_FLAGS & DEBUG_TINY) printf ("T");
+
+	/*
+	**	look for ccb and set the status.
+	*/
+
+	dsa = INL (nc_dsa);
+	cp = &np->ccb;
+	while (cp && (CCB_PHYS (cp, phys) != dsa))
+		cp = cp->link_ccb;
+
+	if (cp) {
+		cp-> host_status = HS_SEL_TIMEOUT;
+		ncr_complete (np, cp);
+	};
+
+	/*
+	**	repair start queue
+	*/
+
+	scratcha = INL (nc_scratcha);
+	diff = scratcha - NCB_SCRIPT_PHYS (np, tryloop);
+
+/*	assert ((diff <= MAX_START * 20) && !(diff % 20));*/
+
+	if ((diff <= MAX_START * 20) && !(diff % 20)) {
+		np->script->startpos[0] = scratcha;
+		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
+		return;
+	};
+	ncr_init (np, "selection timeout", HS_FAIL);
+#ifndef SCSI_NCR_NO_DISCONNECT
+	np->disc = 1;
+#endif
+}
+
+/*==========================================================
+**
+**
+**	ncr chip exception handler for phase errors.
+**
+**
+**==========================================================
+**
+**	We have to construct a new transfer descriptor,
+**	to transfer the rest of the current block.
+**
+**----------------------------------------------------------
+*/
+
+static void ncr_int_ma (ncb_p np)
+{
+	u_int32	dbc;
+	u_int32	rest;
+	u_int32	dsa;
+	u_int32	dsp;
+	u_int32	nxtdsp;
+	u_int32	*vdsp;
+	u_int32	oadr, olen;
+	u_int32	*tblp;
+        ncrcmd *newcmd;
+	u_char	cmd, sbcl, delta, ss0, ss2;
+	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 */
+
+	/*
+	**	locate matching cp
+	*/
+	dsa = INL (nc_dsa);
+	cp = &np->ccb;
+	while (cp && (CCB_PHYS (cp, phys) != dsa))
+		cp = cp->link_ccb;
+
+	if (!cp) {
+	    printf ("%s: SCSI phase error fixup: CCB already dequeued (0x%08lx)\n", 
+		    ncr_name (np), (u_long) np->header.cp);
+	    return;
+	}
+	if (cp != np->header.cp) {
+	    printf ("%s: SCSI phase error fixup: CCB address mismatch (0x%08lx != 0x%08lx)\n", 
+		    ncr_name (np), (u_long) cp, (u_long) np->header.cp);
+	    return;
+	}
+
+	/*
+	**	find the interrupted script command,
+	**	and the address at which to continue.
+	*/
+
+	if (dsp == vtophys (&cp->patch[2])) {
+		vdsp = &cp->patch[0];
+		nxtdsp = vdsp[3];
+	} else if (dsp == vtophys (&cp->patch[6])) {
+		vdsp = &cp->patch[4];
+		nxtdsp = vdsp[3];
+	} else {
+		vdsp = (u_int32 *) ((char*)np->script - np->p_script + 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,
+			(unsigned)dsp,
+			(unsigned)nxtdsp, vdsp, cmd);
+	};
+
+	/*
+	**	get old startaddress and old length.
+	*/
+
+	oadr = vdsp[1];
+
+	if (cmd & 0x10) {	/* Table indirect */
+		tblp = (u_int32 *) ((char*) &cp->phys + oadr);
+		olen = tblp[0];
+		oadr = tblp[1];
+	} else {
+		tblp = (u_int32 *) 0;
+		olen = vdsp[0] & 0xffffff;
+	};
+
+	if (DEBUG_FLAGS & DEBUG_PHASE) {
+		printf ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n",
+			(unsigned) (vdsp[0] >> 24),
+			tblp,
+			(unsigned) olen,
+			(unsigned) oadr);
+	};
+
+	/*
+	**	if old phase not dataphase, leave here.
+	*/
+
+	if (cmd != (vdsp[0] >> 24)) {
+		PRINT_ADDR(cp->cmd);
+		printf ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n",
+			(unsigned)cmd, (unsigned)vdsp[0] >> 24);
+		
+		return;
+	}
+	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));
+		return;
+	};
+
+	/*
+	**	choose the correct patch area.
+	**	if savep points to one, choose the other.
+	*/
+
+	newcmd = cp->patch;
+	if (cp->phys.header.savep == vtophys (newcmd)) newcmd+=4;
+
+	/*
+	**	fillin the commands
+	*/
+
+	newcmd[0] = ((cmd & 0x0f) << 24) | rest;
+	newcmd[1] = oadr + olen - rest;
+	newcmd[2] = SCR_JUMP;
+	newcmd[3] = nxtdsp;
+
+	if (DEBUG_FLAGS & DEBUG_PHASE) {
+		PRINT_ADDR(cp->cmd);
+		printf ("newcmd[%d] %x %x %x %x.\n",
+			(int) (newcmd - cp->patch),
+			(unsigned)newcmd[0],
+			(unsigned)newcmd[1],
+			(unsigned)newcmd[2],
+			(unsigned)newcmd[3]);
+	}
+	/*
+	**	fake the return address (to the patch).
+	**	and restart script processor at dispatcher.
+	*/
+	np->profile.num_break++;
+	OUTL (nc_temp, vtophys (newcmd));
+	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
+}
+
+/*==========================================================
+**
+**
+**      ncr chip exception handler for programmed interrupts.
+**
+**
+**==========================================================
+*/
+
+static int ncr_show_msg (u_char * msg)
+{
+	u_char i;
+	printf ("%x",*msg);
+	if (*msg==M_EXTENDED) {
+		for (i=1;i<8;i++) {
+			if (i-1>msg[1]) break;
+			printf ("-%x",msg[i]);
+		};
+		return (i+1);
+	} else if ((*msg & 0xf0) == 0x20) {
+		printf ("-%x",msg[1]);
+		return (2);
+	};
+	return (1);
+}
+
+void ncr_int_sir (ncb_p np)
+{
+	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;
+	tcb_p	tp     = &np->target[target];
+	int     i;
+	if (DEBUG_FLAGS & DEBUG_TINY) printf ("I#%d", num);
+
+	switch (num) {
+	case SIR_SENSE_RESTART:
+	case SIR_STALL_RESTART:
+		break;
+
+	default:
+		/*
+		**	lookup the ccb
+		*/
+		dsa = INL (nc_dsa);
+		cp = &np->ccb;
+		while (cp && (CCB_PHYS (cp, phys) != dsa))
+			cp = cp->link_ccb;
+
+		assert (cp);
+		if (!cp)
+			goto out;
+		assert (cp == np->header.cp);
+		if (cp != np->header.cp)
+			goto out;
+	}
+
+	switch (num) {
+
+/*--------------------------------------------------------------------
+**
+**	Processing of interrupted getcc selects
+**
+**--------------------------------------------------------------------
+*/
+
+	case SIR_SENSE_RESTART:
+		/*------------------------------------------
+		**	Script processor is idle.
+		**	Look for interrupted "check cond"
+		**------------------------------------------
+		*/
+
+		if (DEBUG_FLAGS & DEBUG_RESTART)
+			printf ("%s: int#%d",ncr_name (np),num);
+		cp = (ccb_p) 0;
+		for (i=0; i<MAX_TARGET; i++) {
+			if (DEBUG_FLAGS & DEBUG_RESTART) printf (" t%d", i);
+			tp = &np->target[i];
+			if (DEBUG_FLAGS & DEBUG_RESTART) printf ("+");
+			cp = tp->hold_cp;
+			if (!cp) continue;
+			if (DEBUG_FLAGS & DEBUG_RESTART) printf ("+");
+			if ((cp->host_status==HS_BUSY) &&
+				(cp->scsi_status==S_CHECK_COND))
+				break;
+			if (DEBUG_FLAGS & DEBUG_RESTART) printf ("- (remove)");
+			tp->hold_cp = cp = (ccb_p) 0;
+		};
+
+		if (cp) {
+			if (DEBUG_FLAGS & DEBUG_RESTART)
+				printf ("+ restart job ..\n");
+			OUTL (nc_dsa, CCB_PHYS (cp, phys));
+			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, getcc));
+			return;
+		};
+
+		/*
+		**	no job, resume normal processing
+		*/
+		if (DEBUG_FLAGS & DEBUG_RESTART) printf (" -- remove trap\n");
+		np->script->start0[0] =  SCR_INT ^ IFFALSE (0);
+		break;
+
+	case SIR_SENSE_FAILED:
+		/*-------------------------------------------
+		**	While trying to select for
+		**	getting the condition code,
+		**	a target reselected us.
+		**-------------------------------------------
+		*/
+		if (DEBUG_FLAGS & DEBUG_RESTART) {
+			PRINT_ADDR(cp->cmd);
+			printf ("in getcc reselect by t%d.\n",
+				(int)INB(nc_ssid) & 0x0f);
+		}
+
+		/*
+		**	Mark this job
+		*/
+		cp->host_status = HS_BUSY;
+		cp->scsi_status = S_CHECK_COND;
+		np->target[cp->cmd->target].hold_cp = cp;
+
+		/*
+		**	And patch code to restart it.
+		*/
+		np->script->start0[0] =  SCR_INT;
+		break;
+
+/*-----------------------------------------------------------------------------
+**
+**	Was Sie schon immer ueber transfermode negotiation wissen wollten ...
+**
+**	We try to negotiate sync and wide transfer only after
+**	a successfull inquire command. We look at byte 7 of the
+**	inquire data to determine the capabilities of the target.
+**
+**	When we try to negotiate, we append the negotiation message
+**	to the identify and (maybe) simple tag message.
+**	The host status field is set to HS_NEGOTIATE to mark this
+**	situation.
+**
+**	If the target doesn't answer this message immidiately
+**	(as required by the standard), the SIR_NEGO_FAIL interrupt
+**	will be raised eventually.
+**	The handler removes the HS_NEGOTIATE status, and sets the
+**	negotiated value to the default (async / nowide).
+**
+**	If we receive a matching answer immediately, we check it
+**	for validity, and set the values.
+**
+**	If we receive a Reject message immediately, we assume the
+**	negotiation has failed, and fall back to standard values.
+**
+**	If we receive a negotiation message while not in HS_NEGOTIATE
+**	state, it's a target initiated negotiation. We prepare a
+**	(hopefully) valid answer, set our parameters, and send back 
+**	this answer to the target.
+**
+**	If the target doesn't fetch the answer (no message out phase),
+**	we assume the negotiation has failed, and fall back to default
+**	settings.
+**
+**	When we set the values, we adjust them in all ccbs belonging 
+**	to this target, in the controller's register, and in the "phys"
+**	field of the controller's struct ncb.
+**
+**	Possible cases:		   hs  sir   msg_in value  send   goto
+**	We try try to negotiate:
+**	-> target doesnt't msgin   NEG FAIL  noop   defa.  -      dispatch
+**	-> target rejected our msg NEG FAIL  reject defa.  -      dispatch
+**	-> target answered  (ok)   NEG SYNC  sdtr   set    -      clrack
+**	-> target answered (!ok)   NEG SYNC  sdtr   defa.  REJ--->msg_bad
+**	-> target answered  (ok)   NEG WIDE  wdtr   set    -      clrack
+**	-> target answered (!ok)   NEG WIDE  wdtr   defa.  REJ--->msg_bad
+**	-> any other msgin	   NEG FAIL  noop   defa.  -      dispatch
+**
+**	Target tries to negotiate:
+**	-> incoming message	   --- SYNC  sdtr   set    SDTR   -
+**	-> incoming message	   --- WIDE  wdtr   set    WDTR   -
+**      We sent our answer:
+**	-> target doesn't msgout   --- PROTO ?      defa.  -      dispatch
+**
+**-----------------------------------------------------------------------------
+*/
+
+	case SIR_NEGO_FAILED:
+		/*-------------------------------------------------------
+		**
+		**	Negotiation failed.
+		**	Target doesn't send an answer message,
+		**	or target rejected our message.
+		**
+		**      Remove negotiation request.
+		**
+		**-------------------------------------------------------
+		*/
+		OUTB (HS_PRT, HS_BUSY);
+
+		/* fall through */
+
+	case SIR_NEGO_PROTO:
+		/*-------------------------------------------------------
+		**
+		**	Negotiation failed.
+		**	Target doesn't fetch the answer message.
+		**
+		**-------------------------------------------------------
+		*/
+
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			PRINT_ADDR(cp->cmd);
+			printf ("negotiation failed sir=%x status=%x.\n",
+				num, cp->nego_status);
+		};
+
+		/*
+		**	any error in negotiation:
+		**	fall back to default mode.
+		*/
+		switch (cp->nego_status) {
+
+		case NS_SYNC:
+			ncr_setsync (np, cp, 0xe0);
+			break;
+
+		case NS_WIDE:
+			ncr_setwide (np, cp, 0);
+			break;
+
+		};
+		np->msgin [0] = M_NOOP;
+		np->msgout[0] = M_NOOP;
+		cp->nego_status = 0;
+		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
+		break;
+
+	case SIR_NEGO_SYNC:
+		/*
+		**	Synchronous request message received.
+		*/
+
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			PRINT_ADDR(cp->cmd);
+			printf ("sync msgin: ");
+			(void) ncr_show_msg (np->msgin);
+			printf (".\n");
+		};
+
+		/*
+		**	get requested values.
+		*/
+
+		chg = 0;
+		per = np->msgin[3];
+		ofs = np->msgin[4];
+		if (ofs==0) per=255;
+
+		/*
+		**      if target sends SDTR message,
+		**	      it CAN transfer synch.
+		*/
+
+		if (ofs)
+			tp->inqdata[7] |= INQ7_SYNC;
+
+		/*
+		**	check values against driver limits.
+		*/
+
+		if (per < np->ns_sync)
+			{chg = 1; per = np->ns_sync;}
+		if (per < tp->minsync)
+			{chg = 1; per = tp->minsync;}
+		if (ofs > tp->maxoffs)
+			{chg = 1; ofs = tp->maxoffs;}
+
+		/*
+		**	Check against controller limits.
+		*/
+		fak = (4ul * per - 1) / np->ns_sync - 3;
+		if (ofs && (fak>7))   {chg = 1; ofs = 0;}
+		if (!ofs) fak=7;
+
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			PRINT_ADDR(cp->cmd);
+			printf ("sync: per=%d ofs=%d fak=%d chg=%d.\n",
+				per, ofs, fak, chg);
+		}
+
+		if (INB (HS_PRT) == HS_NEGOTIATE) {
+			OUTB (HS_PRT, HS_BUSY);
+			switch (cp->nego_status) {
+
+			case NS_SYNC:
+				/*
+				**      This was an answer message
+				*/
+				if (chg) {
+					/*
+					**	Answer wasn't acceptable.
+					*/
+					ncr_setsync (np, cp, 0xe0);
+					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
+				} else {
+					/*
+					**	Answer is ok.
+					*/
+					ncr_setsync (np, cp, (fak<<5)|ofs);
+					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+				};
+				return;
+
+			case NS_WIDE:
+				ncr_setwide (np, cp, 0);
+				break;
+			};
+		};
+
+		/*
+		**	It was a request.
+		**      Check against the table of target capabilities.
+		**      If target not capable force M_REJECT and asynchronous.
+		*/
+		if (np->unit < SCSI_NCR_MAX_HOST) {
+			tp->inqdata[7] &=
+				(target_capabilities[np->unit].and_map[target]);
+			if (!(tp->inqdata[7] & INQ7_SYNC)) {
+				ofs = 0;
+				fak = 7;
+			}
+		}
+
+		/*
+		**	It was a request. Set value and
+		**      prepare an answer message
+		*/
+
+		ncr_setsync (np, cp, (fak<<5)|ofs);
+
+		np->msgout[0] = M_EXTENDED;
+		np->msgout[1] = 3;
+		np->msgout[2] = M_X_SYNC_REQ;
+		np->msgout[3] = per;
+		np->msgout[4] = ofs;
+
+		cp->nego_status = NS_SYNC;
+
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			PRINT_ADDR(cp->cmd);
+			printf ("sync msgout: ");
+			(void) ncr_show_msg (np->msgin);
+			printf (".\n");
+		}
+
+		if (!ofs) {
+			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
+			return;
+		}
+		np->msgin [0] = M_NOOP;
+
+		break;
+
+	case SIR_NEGO_WIDE:
+		/*
+		**	Wide request message received.
+		*/
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			PRINT_ADDR(cp->cmd);
+			printf ("wide msgin: ");
+			(void) ncr_show_msg (np->msgin);
+			printf (".\n");
+		};
+
+		/*
+		**	get requested values.
+		*/
+
+		chg  = 0;
+		wide = np->msgin[3];
+
+		/*
+		**      if target sends WDTR message,
+		**	      it CAN transfer wide.
+		*/
+
+		if (wide)
+			tp->inqdata[7] |= INQ7_WIDE16;
+
+		/*
+		**	check values against driver limits.
+		*/
+
+		if (wide > tp->usrwide)
+			{chg = 1; wide = tp->usrwide;}
+
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			PRINT_ADDR(cp->cmd);
+			printf ("wide: wide=%d chg=%d.\n", wide, chg);
+		}
+
+		if (INB (HS_PRT) == HS_NEGOTIATE) {
+			OUTB (HS_PRT, HS_BUSY);
+			switch (cp->nego_status) {
+
+			case NS_WIDE:
+				/*
+				**      This was an answer message
+				*/
+				if (chg) {
+					/*
+					**	Answer wasn't acceptable.
+					*/
+					ncr_setwide (np, cp, 0);
+					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
+				} else {
+					/*
+					**	Answer is ok.
+					*/
+					ncr_setwide (np, cp, wide);
+					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+				};
+				return;
+
+			case NS_SYNC:
+				ncr_setsync (np, cp, 0xe0);
+				break;
+			};
+		};
+
+		/*
+		**	It was a request, set value and
+		**      prepare an answer message
+		*/
+
+		ncr_setwide (np, cp, wide);
+
+		np->msgout[0] = M_EXTENDED;
+		np->msgout[1] = 2;
+		np->msgout[2] = M_X_WIDE_REQ;
+		np->msgout[3] = wide;
+
+		np->msgin [0] = M_NOOP;
+
+		cp->nego_status = NS_WIDE;
+
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			PRINT_ADDR(cp->cmd);
+			printf ("wide msgout: ");
+			(void) ncr_show_msg (np->msgin);
+			printf (".\n");
+		}
+		break;
+
+/*--------------------------------------------------------------------
+**
+**	Processing of special messages
+**
+**--------------------------------------------------------------------
+*/
+
+	case SIR_REJECT_RECEIVED:
+		/*-----------------------------------------------
+		**
+		**	We received a M_REJECT message.
+		**
+		**-----------------------------------------------
+		*/
+
+		PRINT_ADDR(cp->cmd);
+		printf ("M_REJECT received (%x:%x).\n",
+			(unsigned)np->lastmsg, np->msgout[0]);
+		break;
+
+	case SIR_REJECT_SENT:
+		/*-----------------------------------------------
+		**
+		**	We received an unknown message
+		**
+		**-----------------------------------------------
+		*/
+
+		PRINT_ADDR(cp->cmd);
+		printf ("M_REJECT sent for ");
+		(void) ncr_show_msg (np->msgin);
+		printf (".\n");
+		break;
+
+/*--------------------------------------------------------------------
+**
+**	Processing of special messages
+**
+**--------------------------------------------------------------------
+*/
+
+	case SIR_IGN_RESIDUE:
+		/*-----------------------------------------------
+		**
+		**	We received an IGNORE RESIDUE message,
+		**	which couldn't be handled by the script.
+		**
+		**-----------------------------------------------
+		*/
+
+		PRINT_ADDR(cp->cmd);
+		printf ("M_IGN_RESIDUE received, but not yet implemented.\n");
+		break;
+
+	case SIR_MISSING_SAVE:
+		/*-----------------------------------------------
+		**
+		**	We received an DISCONNECT message,
+		**	but the datapointer wasn't saved before.
+		**
+		**-----------------------------------------------
+		*/
+
+		PRINT_ADDR(cp->cmd);
+		printf ("M_DISCONNECT received, but datapointer not saved:\n"
+			"\tdata=%x save=%x goal=%x.\n",
+			(unsigned) INL (nc_temp),
+			(unsigned) np->header.savep,
+			(unsigned) np->header.goalp);
+		break;
+
+/*--------------------------------------------------------------------
+**
+**	Processing of a "S_QUEUE_FULL" status.
+**
+**	The current command has been rejected,
+**	because there are too many in the command queue.
+**	We have started too many commands for that target.
+**
+**	If possible, reinsert at head of queue.
+**	Stall queue until there are no disconnected jobs
+**	(ncr is REALLY idle). Then restart processing.
+**
+**	We should restart the current job after the controller
+**	has become idle. But this is not yet implemented.
+**
+**--------------------------------------------------------------------
+*/
+	case SIR_STALL_QUEUE:
+		/*-----------------------------------------------
+		**
+		**	Stall the start queue.
+		**
+		**-----------------------------------------------
+		*/
+		PRINT_ADDR(cp->cmd);
+		printf ("queue full.\n");
+
+		np->script->start1[0] =  SCR_INT;
+
+		/*
+		**	Try to disable tagged transfers.
+		*/
+		ncr_setmaxtags (np, &np->target[target], 0);
+
+		/*
+		** @QUEUE@
+		**
+		**	Should update the launch field of the
+		**	current job to be able to restart it.
+		**	Then prepend it to the start queue.
+		*/
+
+		/* fall through */
+
+	case SIR_STALL_RESTART:
+		/*-----------------------------------------------
+		**
+		**	Enable selecting again,
+		**	if NO disconnected jobs.
+		**
+		**-----------------------------------------------
+		*/
+		/*
+		**	Look for a disconnected job.
+		*/
+		cp = &np->ccb;
+		while (cp && cp->host_status != HS_DISCONNECT)
+			cp = cp->link_ccb;
+
+		/*
+		**	if there is one, ...
+		*/
+		if (cp) {
+			/*
+			**	wait for reselection
+			*/
+			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, reselect));
+			return;
+		};
+
+		/*
+		**	else remove the interrupt.
+		*/
+
+		printf ("%s: queue empty.\n", ncr_name (np));
+		np->script->start1[0] =  SCR_INT ^ IFFALSE (0);
+		break;
+	};
+
+out:
+	OUTB (nc_dcntl, (STD|NOCOM));
+}
+
+/*==========================================================
+**
+**
+**	Aquire a control block
+**
+**
+**==========================================================
+*/
+
+static	ccb_p ncr_get_ccb
+	(ncb_p np, u_long target, u_long lun)
+{
+	lcb_p lp;
+	ccb_p cp = (ccb_p) 0;
+
+	/*
+	**	Lun structure available ?
+	*/
+
+	lp = np->target[target].lp[lun];
+	if (lp) {
+		cp = lp->next_ccb;
+
+		/*
+		**	Look for free CCB
+		*/
+
+		while (cp && cp->magic) cp = cp->next_ccb;
+	}
+
+	/*
+	**	if nothing available, take the default.
+	**	DANGEROUS, because this ccb is not suitable for
+	**	reselection.
+	**	If lp->actccbs > 0 wait for a suitable ccb to be free.
+	*/
+	if ((!cp) && lp && lp->actccbs > 0)
+		return ((ccb_p) 0);
+
+	if (!cp) cp = &np->ccb;
+
+	/*
+	**	Wait until available.
+	*/
+#if 0
+	while (cp->magic) {
+		if (flags & SCSI_NOSLEEP) break;
+		if (tsleep ((caddr_t)cp, PRIBIO|PCATCH, "ncr", 0))
+			break;
+	};
+#endif
+
+	if (cp->magic)
+		return ((ccb_p) 0);
+
+	cp->magic = 1;
+	return (cp);
+}
+
+/*==========================================================
+**
+**
+**	Release one control block
+**
+**
+**==========================================================
+*/
+
+void ncr_free_ccb (ncb_p np, ccb_p cp)
+{
+	/*
+	**    sanity
+	*/
+
+	assert (cp != NULL);
+
+	cp -> host_status = HS_IDLE;
+	cp -> magic = 0;
+#if 0
+	if (cp == &np->ccb)
+		wakeup ((caddr_t) cp);
+#endif
+}
+
+/*==========================================================
+**
+**
+**      Allocation of resources for Targets/Luns/Tags.
+**
+**
+**==========================================================
+*/
+
+static	void ncr_alloc_ccb (ncb_p np, u_long target, u_long lun)
+{
+	tcb_p tp;
+	lcb_p lp;
+	ccb_p cp;
+
+	assert (np != NULL);
+
+	if (target>=MAX_TARGET) return;
+	if (lun   >=MAX_LUN   ) return;
+
+	tp=&np->target[target];
+
+	if (!tp->jump_tcb.l_cmd) {
+
+		/*
+		**	initialize it.
+		*/
+		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[1] = vtophys (&tp->sval);
+		tp->getscr[2] = np->paddr + offsetof (struct ncr_reg, nc_sxfer);
+		tp->getscr[3] = SCR_COPY (1);
+		tp->getscr[4] = vtophys (&tp->wval);
+		tp->getscr[5] = np->paddr + offsetof (struct ncr_reg, nc_scntl3);
+
+		assert (( (offsetof(struct ncr_reg, nc_sxfer) ^
+			offsetof(struct tcb    , sval    )) &3) == 0);
+		assert (( (offsetof(struct ncr_reg, nc_scntl3) ^
+			offsetof(struct tcb    , wval    )) &3) == 0);
+
+		tp->call_lun.l_cmd   = (SCR_CALL);
+		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);
+		np->jump_tcb.l_paddr = vtophys (&tp->jump_tcb);
+	}
+
+	/*
+	**	Logic unit control block
+	*/
+	lp = tp->lp[lun];
+	if (!lp) {
+		/*
+		**	Allocate a lcb
+		*/
+		lp = (lcb_p) m_alloc (sizeof (struct lcb));
+		if (!lp) return;
+
+		if (DEBUG_FLAGS & DEBUG_ALLOC) {
+			PRINT_LUN(np, target, lun);
+			printf ("new lcb @%p.\n", lp);
+		}
+
+		/*
+		**	Initialize it
+		*/
+		bzero (lp, sizeof (*lp));
+		lp->jump_lcb.l_cmd   = (SCR_JUMP ^ IFFALSE (DATA (lun)));
+		lp->jump_lcb.l_paddr = tp->jump_lcb.l_paddr;
+
+		lp->call_tag.l_cmd   = (SCR_CALL);
+		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->actlink = 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
+	}
+
+	/*
+	**	Allocate ccbs up to lp->reqccbs.
+	**
+	**	This modification will be reworked in a future release.
+	*/
+
+loop_alloc_ccb:
+
+	/*
+	**	Limit possible number of ccbs.
+	**
+	**	If tagged command queueing is enabled,
+	**	can use more than one ccb.
+	*/
+	if (np->actccbs >= MAX_START-2) return;
+	if (lp->actccbs && (lp->actccbs >= lp->reqccbs))
+		return;
+
+	/*
+	**	Allocate a ccb
+	*/
+	cp = (ccb_p) m_alloc (sizeof (struct ccb));
+	if (!cp)
+		return;
+
+	if (DEBUG_FLAGS & DEBUG_ALLOC) {
+		PRINT_LUN(np, target, lun);
+		printf ("new ccb @%p.\n", cp);
+	}
+
+	/*
+	**	Count it
+	*/
+	lp->actccbs++;
+	np->actccbs++;
+
+	/*
+	**	Initialize it
+	*/
+	bzero (cp, sizeof (*cp));
+
+	/*
+	**	Fill in physical addresses
+	*/
+
+	cp->p_ccb	     = vtophys (cp);
+
+	/*
+	**	Chain into reselect list
+	*/
+	cp->jump_ccb.l_cmd   = SCR_JUMP;
+	cp->jump_ccb.l_paddr = lp->jump_ccb.l_paddr;
+	lp->jump_ccb.l_paddr = CCB_PHYS (cp, jump_ccb);
+	cp->call_tmp.l_cmd   = SCR_CALL;
+	cp->call_tmp.l_paddr = NCB_SCRIPT_PHYS (np, resel_tmp);
+
+	/*
+	**	Chain into wakeup list
+	*/
+	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;
+
+goto loop_alloc_ccb;
+}
+
+/*==========================================================
+**
+**
+**	Build Scatter Gather Block
+**
+**
+**==========================================================
+**
+**	The transfer area may be scattered among
+**	several non adjacent physical pages.
+**
+**	We may use MAX_SCATTER blocks.
+**
+**----------------------------------------------------------
+*/
+
+/*	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.
+**	If we wanted to avoid unexpected phase changes at all
+**	we had to use a break point every 512 bytes.
+**	Of course the number of scatter/gather blocks is
+**	limited.
+*/
+
+/*
+**	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;
+
+			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++;
+		}
+
+		return datalen ? -1 : o_segment;
+	}
+
+	/*
+	**	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;
+		}
+	}
+
+	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;
+	}
+
+	return segment < cmd->use_sg ? -1 : segment;
+}
+#endif /* SCSI_NCR_SEGMENT_SIZE */
+
+/*==========================================================
+**
+**
+**	Test the pci bus snoop logic :-(
+**
+**	Has to be called with interrupts disabled.
+**
+**
+**==========================================================
+*/
+
+#ifndef NCR_IOMAPPED
+static int ncr_regtest (struct ncb* np)
+{
+	register volatile u_long data;
+	/*
+	**	ncr registers may NOT be cached.
+	**	write 0xffffffff to a read only register area,
+	**	and try to read it back.
+	*/
+	data = 0xffffffff;
+	OUTL_OFF(offsetof(struct ncr_reg, nc_dstat), data);
+	data = INL_OFF(offsetof(struct ncr_reg, nc_dstat));
+#if 1
+	if (data == 0xffffffff) {
+#else
+	if ((data & 0xe2f0fffd) != 0x02000080) {
+#endif
+		printf ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n",
+			(unsigned) data);
+		return (0x10);
+	};
+	return (0);
+}
+#endif
+
+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) {
+            err |= ncr_regtest (np);
+            if (err) return (err);
+	}
+#endif
+	/*
+	**	init
+	*/
+	pc  = NCB_SCRIPT_PHYS (np, snooptest);
+	host_wr = 1;
+	ncr_wr  = 2;
+	/*
+	**	Set memory and register.
+	*/
+	np->ncr_cache = host_wr;
+	OUTL (nc_temp, ncr_wr);
+	/*
+	**	Start script (exchange values)
+	*/
+	OUTL (nc_dsp, pc);
+	/*
+	**	Wait 'til done (with timeout)
+	*/
+	for (i=0; i<NCR_SNOOP_TIMEOUT; i++)
+		if (INB(nc_istat) & (INTF|SIP|DIP))
+			break;
+	/*
+	**	Save termination position.
+	*/
+	pc = INL (nc_dsp);
+	/*
+	**	Read memory and register.
+	*/
+	host_rd = np->ncr_cache;
+	ncr_rd  = INL (nc_scratcha);
+	ncr_bk  = INL (nc_temp);
+	/*
+	**	Reset ncr chip
+	*/
+	OUTB (nc_istat,  SRST);
+	DELAY (1000);
+	OUTB (nc_istat,  0   );
+	/*
+	**	check for timeout
+	*/
+	if (i>=NCR_SNOOP_TIMEOUT) {
+		printf ("CACHE TEST FAILED: timeout.\n");
+		return (0x20);
+	};
+	/*
+	**	Check termination position.
+	*/
+	if (pc != NCB_SCRIPT_PHYS (np, snoopend)+8) {
+		printf ("CACHE TEST FAILED: script execution failed.\n");
+		return (0x40);
+	};
+	/*
+	**	Show results.
+	*/
+	if (host_wr != ncr_rd) {
+		printf ("CACHE TEST FAILED: host wrote %d, ncr read %d.\n",
+			(int) host_wr, (int) ncr_rd);
+		err |= 1;
+	};
+	if (host_rd != ncr_wr) {
+		printf ("CACHE TEST FAILED: ncr wrote %d, host read %d.\n",
+			(int) ncr_wr, (int) host_rd);
+		err |= 2;
+	};
+	if (ncr_bk != ncr_wr) {
+		printf ("CACHE TEST FAILED: ncr wrote %d, read back %d.\n",
+			(int) ncr_wr, (int) ncr_bk);
+		err |= 4;
+	};
+	return (err);
+}
+
+/*==========================================================
+**
+**
+**	Profiling the drivers and targets performance.
+**
+**
+**==========================================================
+*/
+
+/*
+**	Compute the difference in milliseconds.
+**/
+
+#ifdef SCSI_NCR_PROFILE
+
+static	int ncr_delta (u_long from, u_long to)
+{
+	if (!from) return (-1);
+	if (!to) return (-2);
+	return ((to  - from) * 1000 / HZ );
+}
+
+#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;
+	u_long diff;
+
+	PROFILE.end = jiffies;
+
+	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 */
+
+	en = ncr_delta (PROFILE.start,PROFILE.end),
+	di = ncr_delta (PROFILE.start,PROFILE.disconnect),
+	se = ncr_delta (PROFILE.start,PROFILE.select);
+	post = en - st;
+
+	/*
+	**	@PROFILE@  Disconnect time invalid if multiple disconnects
+	*/
+
+	if (di>=0) disc = se-di; else  disc = 0;
+
+	work = (st - co) - disc;
+
+	diff = (np->disc_phys - np->disc_ref) & 0xff;
+	np->disc_ref += diff;
+
+	np->profile.num_trans	+= 1;
+	if (cp->cmd) {
+		np->profile.num_kbytes	+= (cp->cmd->request_bufflen >> 10);
+		np->profile.rest_bytes	+= (cp->cmd->request_bufflen & (0x400-1));
+		if (np->profile.rest_bytes >= 0x400) {
+			++np->profile.num_kbytes;
+			np->profile.rest_bytes	-= 0x400;
+		}
+	}
+	np->profile.num_disc	+= diff;
+	np->profile.ms_setup	+= co;
+	np->profile.ms_data	+= work;
+	np->profile.ms_disc	+= disc;
+	np->profile.ms_post	+= post;
+}
+#undef PROFILE
+
+#endif /* SCSI_NCR_PROFILE */
+
+/*==========================================================
+**
+**
+**	Device lookup.
+**
+**	@GENSCSI@ should be integrated to scsiconf.c
+**
+**
+**==========================================================
+*/
+
+struct table_entry {
+	char *	manufacturer;
+	char *	model;
+	char *	version;
+	u_long	info;
+};
+
+static struct table_entry device_tab[] =
+{
+#ifdef NCR_GETCC_WITHMSG
+	{"", "", "", QUIRK_NOMSG},
+	{"SONY", "SDT-5000", "3.17", QUIRK_NOMSG},
+	{"WangDAT", "Model 2600", "01.7", QUIRK_NOMSG},
+	{"WangDAT", "Model 3200", "02.2", QUIRK_NOMSG},
+	{"WangDAT", "Model 1300", "02.4", QUIRK_NOMSG},
+#endif
+	{"", "", "", 0} /* catch all: must be last entry. */
+};
+
+static u_long ncr_lookup(char * id)
+{
+	struct table_entry * p = device_tab;
+	char *d, *r, c;
+
+	for (;;p++) {
+
+		d = id+8;
+		r = p->manufacturer;
+		while ((c=*r++)) if (c!=*d++) break;
+		if (c) continue;
+
+		d = id+16;
+		r = p->model;
+		while ((c=*r++)) if (c!=*d++) break;
+		if (c) continue;
+
+		d = id+32;
+		r = p->version;
+		while ((c=*r++)) if (c!=*d++) break;
+		if (c) continue;
+
+		return (p->info);
+	}
+}
+
+/*==========================================================
+**
+**	Determine the ncr's clock frequency.
+**	This is important for the negotiation
+**	of the synchronous transfer rate.
+**
+**==========================================================
+**
+**	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.
+**
+**----------------------------------------------------------
+*/
+
+#ifndef NCR_CLOCK
+#	define NCR_CLOCK 40
+#endif /* NCR_CLOCK */
+
+
+static void ncr_getclock (ncb_p np)
+{
+	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);
+}
+
+/*===================== LINUX ENTRY POINTS SECTION ==========================*/
+
+#ifndef uchar
+#define uchar unsigned char
+#endif
+
+#ifndef ushort
+#define ushort unsigned short
+#endif
+
+#ifndef ulong
+#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
+*/
+
+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}
+};
+
+#define NPCI_CHIP_IDS (sizeof (pci_chip_ids) / sizeof(pci_chip_ids[0]))
+
+/*
+**   Linux entry point for NCR53C8XX devices detection routine.
+**
+**   Called by the middle-level scsi drivers at initialization time,
+**   or at module installation.
+**
+**   Read the PCI configuration and try to attach each
+**   detected NCR board.
+**
+**   Returns the number of boards successfully attached.
+*/
+
+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 */
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
+     tpnt->proc_dir = &proc_scsi_ncr53c8xx;
+# ifdef SCSI_NCR_PROC_INFO_SUPPORT
+     tpnt->proc_info = ncr53c8xx_proc_info;
+# 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;
+     }
+
+     return count;
+}
+
+
+/*
+**   Read the PCI configuration of a found NCR board and
+**   try yo attach it.
+*/
+
+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; 
+#else
+     ulong base, io_port; 
+#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;
+     }
+
+     return ncr_attach (tpnt, unit, device_id, revision, chip, base, io_port, 
+		       (int) irq, bus, (uchar) device_fn);
+}
+
+
+/*
+**   Linux entry point of queuecommand() function
+*/
+
+int ncr53c8xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
+{
+     int sts;
+#ifdef DEBUG
+printk("ncr53c8xx_queue_command\n");
+#endif
+
+     if ((sts = ncr_queue_command(cmd, done)) != DID_OK) {
+	  cmd->result = ScsiResult(sts, 0);
+	  done(cmd);
+#ifdef DEBUG
+printk("ncr53c8xx : command not queued - result=%d\n", sts);
+#endif
+          return sts;
+     }
+#ifdef DEBUG
+printk("ncr53c8xx : command successfully queued\n");
+#endif
+     return sts;
+}
+
+/*
+**   Linux entry point of the interrupt handler
+*/
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
+static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
+#else
+static void ncr53c8xx_intr(int irq, struct pt_regs * regs)
+#endif
+{
+     struct Scsi_Host *host;
+     struct host_data *host_data;
+
+#ifdef DEBUG
+printk("ncr53c8xx : interrupt received\n");
+#endif
+
+     for (host = first_host; host; host = host->next) {
+	  if (host->hostt == the_template && host->irq == irq) {
+	       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)
+	       	    ncr_intr(&host_data->ncb_data);
+#   endif
+#endif
+	       ncr_intr(&host_data->ncb_data);
+	  }
+     }
+}
+
+/*
+**   Linux entry point of the timer handler
+*/
+
+static void ncr53c8xx_timeout(unsigned long np)
+{
+     ncr_timeout((ncb_p) np);
+}
+
+/*
+**   Linux entry point of reset() function
+*/
+
+#if	LINUX_VERSION_CODE >= LinuxVersionCode(1,3,98)
+int ncr53c8xx_reset(Scsi_Cmnd *cmd, unsigned int reset_flags)
+#else
+int ncr53c8xx_reset(Scsi_Cmnd *cmd)
+#endif
+{
+#ifdef DEBUG
+printk("ncr53c8xx_reset : reset call\n");
+#endif
+	return ncr_reset_bus(cmd);
+}
+
+/*
+**   Linux entry point of abort() function
+*/
+
+int ncr53c8xx_abort(Scsi_Cmnd *cmd)
+{
+printk("ncr53c8xx_abort : abort call\n");
+	return ncr_abort_command(cmd);
+}
+
+#ifdef MODULE
+int ncr53c8xx_release(struct Scsi_Host *host)
+{
+     struct host_data *host_data;
+#ifdef DEBUG
+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);
+	  }
+     }
+
+     return 1;
+}
+#endif
+
+
+/*
+**	Scsi command waiting list management.
+**
+**	It may happen that we cannot insert a scsi command into the start queue,
+**	in the following circumstances.
+** 		Too few preallocated ccb(s), 
+**		maxtags < cmd_per_lun of the Linux host control block,
+**		etc...
+**	Such scsi commands are inserted into a waiting list.
+**	When a scsi command complete, we try to requeue the commands of the
+**	waiting list.
+*/
+
+#define next_wcmd host_scribble
+
+static void insert_into_waiting_list(ncb_p np, Scsi_Cmnd *cmd)
+{
+	Scsi_Cmnd *wcmd;
+
+#ifdef DEBUG_WAITING_LIST
+	printf("%s: cmd %lx inserted into waiting list\n", ncr_name(np), (u_long) cmd);
+#endif
+	cmd->next_wcmd = 0;
+	if (!(wcmd = np->waiting_list)) np->waiting_list = cmd;
+	else {
+		while ((wcmd->next_wcmd) != 0)
+			wcmd = (Scsi_Cmnd *) wcmd->next_wcmd;
+		wcmd->next_wcmd = (char *) cmd;
+	}
+}
+
+static Scsi_Cmnd *remove_from_waiting_list(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;
+#ifdef DEBUG_WAITING_LIST
+	printf("%s: cmd %lx removed from waiting list\n", ncr_name(np), (u_long) cmd);
+#endif
+			return cmd;
+		}
+	}
+	return 0;
+}
+
+static void process_waiting_list(ncb_p np, int sts)
+{
+	Scsi_Cmnd *waiting_list, *wcmd;
+
+	waiting_list = np->waiting_list;
+	np->waiting_list = 0;
+
+#ifdef DEBUG_WAITING_LIST
+	if (waiting_list) printf("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts);
+#endif
+	while ((wcmd = waiting_list) != 0) {
+		waiting_list = (Scsi_Cmnd *) wcmd->next_wcmd;
+		wcmd->next_wcmd = 0;
+		if (sts == DID_OK) {
+#ifdef DEBUG_WAITING_LIST
+	printf("%s: cmd %lx trying to requeue\n", ncr_name(np), (u_long) wcmd);
+#endif
+			sts = ncr_queue_command(wcmd, wcmd->scsi_done);
+		}
+		if (sts != DID_OK) {
+#ifdef DEBUG_WAITING_LIST
+	printf("%s: cmd %lx done forced sts=%d\n", ncr_name(np), (u_long) wcmd, sts);
+#endif
+			wcmd->result = ScsiResult(sts, 0);
+			wcmd->scsi_done(wcmd);
+		}
+	}
+}
+
+#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.
+*/
+
+static int guess_xfer_direction(int opcode)
+{
+	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 */
+		d = XferNone;
+		break;
+	default:
+		d = XferIn;
+		break;
+	}
+
+	return d;
+}
+
+
+#ifdef SCSI_NCR_PROC_INFO_SUPPORT
+
+/*=========================================================================
+**	Proc file system stuff
+**
+**	A read operation returns profile information.
+**	A write operation is a control command.
+**	The string is parsed in the driver code and the command is passed 
+**	to the ncr_usercmd() function.
+**=========================================================================
+*/
+
+#define is_digit(c)	((c) >= '0' && (c) <= '9')
+#define digit_to_bin(c)	((c) - '0')
+#define is_space(c)	((c) == ' ' || (c) == '\t')
+
+static int skip_spaces(char *ptr, int len)
+{
+	int cnt, c;
+
+	for (cnt = len; cnt > 0 && (c = *ptr++) && is_space(c); cnt--);
+
+	return (len - cnt);
+}
+
+static int get_int_arg(char *ptr, int len, u_long *pv)
+{
+	int	cnt, c;
+	u_long	v;
+
+	for (v = 0, cnt = len; cnt > 0 && (c = *ptr++) && is_digit(c); cnt--) {
+		v = (v * 10) + digit_to_bin(c);
+	}
+
+	if (pv)
+		*pv = v;
+
+	return (len - cnt);
+}
+
+static int is_keyword(char *ptr, int len, char *verb)
+{
+	int verb_len = strlen(verb);
+
+	if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len))
+		return verb_len;
+	else
+		return 0;
+
+}
+
+#define SKIP_SPACES(min_spaces)						\
+	if ((arg_len = skip_spaces(ptr, len)) < (min_spaces))		\
+		return -EINVAL;						\
+	ptr += arg_len; len -= arg_len;
+
+#define GET_INT_ARG(v)							\
+	if (!(arg_len = get_int_arg(ptr, len, &(v))))			\
+		return -EINVAL;						\
+	ptr += arg_len; len -= arg_len;
+
+
+/*
+**	Parse a control command
+*/
+
+static int ncr_user_command(ncb_p np, char *buffer, int length)
+{
+	char *ptr	= buffer;
+	int len		= length;
+	struct usrcmd	 *uc = &np->user;
+	int		arg_len;
+	u_long 		target;
+
+	bzero(uc, sizeof(*uc));
+
+	if (len > 0 && ptr[len-1] == '\n')
+		--len;
+
+	if	((arg_len = is_keyword(ptr, len, "setsync")) != 0)
+		uc->cmd = UC_SETSYNC;
+	else if	((arg_len = is_keyword(ptr, len, "settags")) != 0)
+		uc->cmd = UC_SETTAGS;
+	else if	((arg_len = is_keyword(ptr, len, "setorder")) != 0)
+		uc->cmd = UC_SETORDER;
+	else if	((arg_len = is_keyword(ptr, len, "setwide")) != 0)
+		uc->cmd = UC_SETWIDE;
+	else if	((arg_len = is_keyword(ptr, len, "setdebug")) != 0)
+		uc->cmd = UC_SETDEBUG;
+	else if	((arg_len = is_keyword(ptr, len, "setflag")) != 0)
+		uc->cmd = UC_SETFLAG;
+	else if	((arg_len = is_keyword(ptr, len, "clearprof")) != 0)
+		uc->cmd = UC_CLEARPROF;
+	else
+		arg_len = 0;
+
+#ifdef DEBUG_PROC_INFO
+printf("ncr_user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd);
+#endif
+
+	if (!arg_len)
+		return -EINVAL;
+	ptr += arg_len; len -= arg_len;
+
+	switch(uc->cmd) {
+	case UC_SETSYNC:
+	case UC_SETTAGS:
+	case UC_SETWIDE:
+	case UC_SETFLAG:
+		SKIP_SPACES(1);
+		GET_INT_ARG(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;
+	}
+
+	switch(uc->cmd) {
+	case UC_SETSYNC:
+	case UC_SETTAGS:
+	case UC_SETWIDE:
+		SKIP_SPACES(1);
+		GET_INT_ARG(uc->data);
+#ifdef DEBUG_PROC_INFO
+printf("ncr_user_command: data=%ld\n", uc->data);
+#endif
+		break;
+	case UC_SETORDER:
+		SKIP_SPACES(1);
+		if	((arg_len = is_keyword(ptr, len, "simple")))
+			uc->data = M_SIMPLE_TAG;
+		else if	((arg_len = is_keyword(ptr, len, "ordered")))
+			uc->data = M_ORDERED_TAG;
+		else if	((arg_len = is_keyword(ptr, len, "default")))
+			uc->data = 0;
+		else
+			return -EINVAL;
+		break;
+	case UC_SETDEBUG:
+		while (len > 0) {
+			SKIP_SPACES(1);
+			if	((arg_len = is_keyword(ptr, len, "alloc")))
+				uc->data |= DEBUG_ALLOC;
+			else if	((arg_len = is_keyword(ptr, len, "poll")))
+				uc->data |= DEBUG_POLL;
+			else if	((arg_len = is_keyword(ptr, len, "queue")))
+				uc->data |= DEBUG_QUEUE;
+			else if	((arg_len = is_keyword(ptr, len, "result")))
+				uc->data |= DEBUG_RESULT;
+			else if	((arg_len = is_keyword(ptr, len, "scatter")))
+				uc->data |= DEBUG_SCATTER;
+			else if	((arg_len = is_keyword(ptr, len, "script")))
+				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, "nego")))
+				uc->data |= DEBUG_NEGO;
+			else if	((arg_len = is_keyword(ptr, len, "tags")))
+				uc->data |= DEBUG_TAGS;
+			else if	((arg_len = is_keyword(ptr, len, "freeze")))
+				uc->data |= DEBUG_FREEZE;
+			else if	((arg_len = is_keyword(ptr, len, "restart")))
+				uc->data |= DEBUG_RESTART;
+			else
+				return -EINVAL;
+			ptr += arg_len; len -= arg_len;
+		}
+#ifdef DEBUG_PROC_INFO
+printf("ncr_user_command: data=%ld\n", uc->data);
+#endif
+		break;
+	case UC_SETFLAG:
+		while (len > 0) {
+			SKIP_SPACES(1);
+			if	((arg_len = is_keyword(ptr, len, "trace")))
+				uc->data |= UF_TRACE;
+			else
+				return -EINVAL;
+			ptr += arg_len; len -= arg_len;
+		}
+		break;
+	default:
+		break;
+	}
+
+	if (len)
+		return -EINVAL;
+#ifdef SCSI_NCR_USER_COMMAND
+	else {
+		long flags;
+
+		save_flags(flags); cli();
+		ncr_usercmd (np);
+		restore_flags(flags);
+	}
+#endif
+	return length;
+}
+
+struct info_str
+{
+	char *buffer;
+	int length;
+	int offset;
+	int pos;
+};
+
+static void copy_mem_info(struct info_str *info, char *data, int len)
+{
+	if (info->pos + len > info->length)
+		len = info->length - info->pos;
+
+	if (info->pos + len < info->offset) {
+		info->pos += len;
+		return;
+	}
+	if (info->pos < info->offset) {
+		data += (info->offset - info->pos);
+		len  -= (info->offset - info->pos);
+	}
+
+	if (len > 0) {
+		memcpy(info->buffer + info->pos, data, len);
+		info->pos += len;
+	}
+}
+
+static int copy_info(struct info_str *info, char *fmt, ...)
+{
+	va_list args;
+	char buf[81];
+	int len;
+
+	va_start(args, fmt);
+	len = vsprintf(buf, fmt, args);
+	va_end(args);
+
+	copy_mem_info(info, buf, len);
+	return len;
+}
+
+/*
+**	Copy formatted profile informations into the input buffer.
+*/
+
+static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len)
+{
+	struct info_str info;
+
+	info.buffer	= ptr;
+	info.length	= len;
+	info.offset	= offset;
+	info.pos	= 0;
+
+	copy_info(&info, "General informations:\n");
+	copy_info(&info, "  Chip NCR53C%03d, ",	np->chip);
+	copy_info(&info, "device id 0x%x, ",	np->device_id);
+	copy_info(&info, "revision id 0x%x\n",	np->revision_id);
+
+	copy_info(&info, "  IO port address 0x%lx, ", (u_long) np->port);
+	copy_info(&info, "IRQ number %d\n", (int) np->irq);
+
+#ifndef SCSI_NCR_IOMAPPED
+	if (np->use_mmio)
+		copy_info(&info, "  Using memory mapped IO at virtual address 0x%lx\n",
+		                  (u_long) np->reg_remapped);
+#endif
+
+#ifdef SCSI_NCR_PROFILE
+	copy_info(&info, "Profiling informations:\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);
+	copy_info(&info, "  %-12s = %lu\n", "num_disc",	np->profile.num_disc);
+	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);
+#endif
+	
+	return info.pos > info.offset? info.pos - info.offset : 0;
+}
+
+/*
+**	Entry point of the scsi proc fs of the driver.
+**	- func = 0 means read  (returns profile data)
+**	- func = 1 means write (parse user control command)
+*/
+
+int ncr53c8xx_proc_info(char *buffer, char **start, off_t offset,
+			int length, int hostno, int func)
+{
+	struct Scsi_Host *host;
+	struct host_data *host_data;
+	ncb_p ncb = 0;
+	int retv;
+
+#ifdef DEBUG_PROC_INFO
+printf("ncr53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func);
+#endif
+
+	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;
+			break;
+		}
+	}
+
+	if (!ncb)
+		return -EINVAL;
+
+	if (func) {
+		retv = ncr_user_command(ncb, buffer, length);
+#ifdef DEBUG_PROC_INFO
+printf("ncr_user_command: retv=%d\n", retv);
+#endif
+	}
+	else {
+		if (*start)
+			*start = buffer;
+		retv = ncr_host_info(ncb, buffer, offset, length);
+	}
+
+	return retv;
+}
+
+/*=========================================================================
+**	End of proc file system stuff
+**=========================================================================
+*/
+#endif
+
+/*
+**	Module stuff
+*/
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = NCR53C8XX;
+#include "scsi_module.c"
+#endif
diff -u --recursive --new-file v2.0.2/linux/drivers/scsi/ncr53c8xx.h linux/drivers/scsi/ncr53c8xx.h
--- v2.0.2/linux/drivers/scsi/ncr53c8xx.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/ncr53c8xx.h	Sat Jul  6 12:06:37 1996
@@ -0,0 +1,849 @@
+/******************************************************************************
+**  Device driver for the PCI-SCSI NCR538XX controller family.
+**
+**  Copyright (C) 1994  Wolfgang Stanglmeier
+**
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**-----------------------------------------------------------------------------
+**
+**  This driver has been ported to Linux from the FreeBSD NCR53C8XX driver
+**  and is currently maintained by
+**
+**          Gerard Roudier              <groudier@club-internet.fr>
+**
+**  Being given that this driver originates from the FreeBSD version, and
+**  in order to keep synergy on both, any suggested enhancements and corrections
+**  received on Linux are automatically a potential candidate for the FreeBSD 
+**  version.
+**
+**  The original driver has been written for 386bsd and FreeBSD by
+**          Wolfgang Stanglmeier        <wolf@cologne.de>
+**          Stefan Esser                <se@mi.Uni-Koeln.de>
+**
+**  And has been ported to NetBSD by
+**          Charles M. Hannum           <mycroft@gnu.ai.mit.edu>
+**
+*******************************************************************************
+*/
+
+#ifndef NCR53C8XX_H
+#define NCR53C8XX_H
+
+/*********** LINUX SPECIFIC SECTION ******************/
+
+/*
+**	Check supported Linux versions
+*/
+
+#if !defined(LINUX_VERSION_CODE)
+#include <linux/version.h>
+#endif
+#include <linux/config.h>
+
+/*
+**	During make dep of linux-1.2.13, LINUX_VERSION_CODE is undefined
+**	Under linux-1.3.X, all seems to be OK.
+**	So, we have only to define it under 1.2.13
+*/
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
+#if !defined(LINUX_VERSION_CODE)
+#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.
+**
+**	Memory mapped IO only works with linux-1.3.X
+**	If your motherboard does not work with memory mapped IO,
+**	define SCSI_NCR_IOMAPPED for PATCHLEVEL 3 too.
+*/
+
+#if	LINUX_VERSION_CODE < LinuxVersionCode(1,3,0)
+#	define	SCSI_NCR_IOMAPPED
+#endif
+
+#if	LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
+#	define	SCSI_NCR_PROC_INFO_SUPPORT
+#endif
+
+#if	LINUX_VERSION_CODE >= LinuxVersionCode(1,3,72)
+#	define SCSI_NCR_SHARE_IRQ
+#endif
+
+/*
+**	Avoid to change these constants, unless you know what you are doing.
+*/
+
+#define SCSI_NCR_MAX_TAGS	(4)
+#define SCSI_NCR_ALWAYS_SIMPLE_TAG
+
+#ifdef CONFIG_SCSI_NCR53C8XX_IOMAPPED
+#define	SCSI_NCR_IOMAPPED
+#endif
+
+#ifndef CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE
+#define SCSI_NCR_TAGGED_QUEUE_DISABLED
+#endif
+
+#ifdef CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
+#define SCSI_NCR_NO_DISCONNECT
+#endif
+
+#ifdef CONFIG_SCSI_NCR53C8XX_FORCE_ASYNCHRONOUS
+#define SCSI_NCR_FORCE_ASYNCHRONOUS
+#endif
+
+#ifdef CONFIG_SCSI_NCR53C8XX_FORCE_SYNC_NEGO
+#define SCSI_NCR_FORCE_SYNC_NEGO
+#endif
+
+#ifdef CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK
+#define SCSI_NCR_DISABLE_MPARITY_CHECK
+#endif
+
+#ifdef CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK
+#define SCSI_NCR_DISABLE_PARITY_CHECK
+#endif
+
+#if 0
+#define SCSI_NCR_SEGMENT_SIZE	(512)
+#endif
+
+#define SCSI_NCR_MAX_SCATTER	(128)
+#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)
+
+#if 1 /* defined CONFIG_SCSI_MULTI_LUN */
+#define SCSI_NCR_MAX_LUN	(8)
+#else
+#define SCSI_NCR_MAX_LUN	(1)
+#endif
+
+#define SCSI_NCR_TIMER_INTERVAL	((HZ+5-1)/5)
+
+/*
+**	Define Scsi_Host_Template parameters
+**
+**	Used by hosts.c and ncr53c8xx.c with module configuration.
+*/
+
+#if defined(HOSTS_C) || defined(MODULE)
+
+#if	LINUX_VERSION_CODE >= LinuxVersionCode(1,3,98)
+#include <scsi/scsicam.h>
+#else
+#include <linux/scsicam.h>
+#endif
+
+int ncr53c8xx_abort(Scsi_Cmnd *);
+int ncr53c8xx_detect(Scsi_Host_Template *tpnt);
+int ncr53c8xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+
+#if	LINUX_VERSION_CODE >= LinuxVersionCode(1,3,98)
+int ncr53c8xx_reset(Scsi_Cmnd *, unsigned int);
+#else
+int ncr53c8xx_reset(Scsi_Cmnd *);
+#endif
+
+#ifdef MODULE
+int ncr53c8xx_release(struct Scsi_Host *);
+#else
+#define ncr53c8xx_release NULL
+#endif
+
+#if	LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
+
+#define NCR53C8XX {NULL,NULL,NULL,NULL,"ncr53c8xx (rel 1.12a)", 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,\
+	/* id */ 7, SCSI_NCR_SG_TABLESIZE /* SG */, /* cmd per lun */ SCSI_NCR_CMD_PER_LUN, 		\
+        /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING} 
+
+
+#else
+
+
+#define NCR53C8XX {NULL, NULL, "ncr53c8xx (rel 1.12a)", 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,\
+	/* id */ 7, SCSI_NCR_SG_TABLESIZE /* SG */, /* cmd per lun */ SCSI_NCR_CMD_PER_LUN, 		\
+        /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING} 
+
+#endif /* LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) */
+
+#endif /* defined(HOSTS_C) || defined(MODULE) */ 
+
+
+#ifndef HOSTS_C
+
+/*
+**	Define the table of target capabilities by host and target
+**
+**	If you have problems with a scsi device, note the host unit and the
+**	corresponding target number.
+**
+**	Edit the corresponding entry of the table below and try successively:
+**		NQ7_Questionnable
+**		NQ7_IdeLike
+**
+**	This bitmap is anded with the byte 7 of inquiry data on completion of
+**	INQUIRY command.
+**	The driver never see the zeroed bits and will ignore the corresponding
+**	capabilities of the target.
+*/
+
+#define INQ7_SftRe	1
+#define INQ7_CmdQueue	(1<<1)		/* Tagged Command */
+#define INQ7_Reserved	(1<<2)
+#define INQ7_Linked	(1<<3)
+#define INQ7_Sync	(1<<4)		/* Synchronous Negotiation */
+#define INQ7_WBus16	(1<<5)
+#define INQ7_WBus32	(1<<6)
+#define INQ7_RelAdr	(1<<7)
+
+#define INQ7_IdeLike		0
+#define INQ7_Scsi1Like		INQ7_IdeLike
+#define INQ7_Perfect		0xff
+#define INQ7_Questionnable	~(INQ7_CmdQueue|INQ7_Sync)
+#define INQ7_VeryQuestionnable	\
+			~(INQ7_CmdQueue|INQ7_Sync|INQ7_WBus16|INQ7_WBus32)
+
+#define INQ7_Default		INQ7_Perfect
+
+#define NCR53C8XX_TARGET_CAPABILITIES					\
+/* Host 0 */								\
+{									\
+	{								\
+	/* Target  0 */		INQ7_Default,				\
+	/* Target  1 */		INQ7_Default,				\
+	/* Target  2 */		INQ7_Default,				\
+	/* Target  3 */		INQ7_Default,				\
+	/* Target  4 */		INQ7_Default,				\
+	/* Target  5 */		INQ7_Default,				\
+	/* Target  6 */		INQ7_Default,				\
+	/* Target  7 */		INQ7_Default,				\
+	/* Target  8 */		INQ7_Default,				\
+	/* Target  9 */		INQ7_Default,				\
+	/* Target 10 */		INQ7_Default,				\
+	/* Target 11 */		INQ7_Default,				\
+	/* Target 12 */		INQ7_Default,				\
+	/* Target 13 */		INQ7_Default,				\
+	/* Target 14 */		INQ7_Default,				\
+	/* Target 15 */		INQ7_Default,				\
+	}								\
+},									\
+/* Host 1 */								\
+{									\
+	{								\
+	/* Target  0 */		INQ7_Default,				\
+	/* Target  1 */		INQ7_Default,				\
+	/* Target  2 */		INQ7_Default,				\
+	/* Target  3 */		INQ7_Default,				\
+	/* Target  4 */		INQ7_Default,				\
+	/* Target  5 */		INQ7_Default,				\
+	/* Target  6 */		INQ7_Default,				\
+	/* Target  7 */		INQ7_Default,				\
+	/* Target  8 */		INQ7_Default,				\
+	/* Target  9 */		INQ7_Default,				\
+	/* Target 10 */		INQ7_Default,				\
+	/* Target 11 */		INQ7_Default,				\
+	/* Target 12 */		INQ7_Default,				\
+	/* Target 13 */		INQ7_Default,				\
+	/* Target 14 */		INQ7_Default,				\
+	/* Target 15 */		INQ7_Default,				\
+	}								\
+}
+
+/*
+**	Replace the proc_dir_entry of the standard ncr driver.
+*/
+
+#if	LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
+#if	defined(CONFIG_SCSI_NCR53C7xx) || !defined(CONFIG_SCSI_NCR53C8XX)
+#define PROC_SCSI_NCR53C8XX	PROC_SCSI_NCR53C7xx
+#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 ******************/
+
+/*-----------------------------------------------------------------
+**
+**	The ncr 53c810 register structure.
+**
+**-----------------------------------------------------------------
+*/
+
+struct ncr_reg {
+/*00*/  u_char    nc_scntl0;    /* full arb., ena parity, par->ATN  */
+
+/*01*/  u_char    nc_scntl1;    /* no reset                         */
+        #define   ISCON   0x10  /* connected to scsi		    */
+        #define   CRST    0x08  /* force reset                      */
+
+/*02*/  u_char    nc_scntl2;    /* no disconnect expected           */
+	#define   SDU     0x80  /* cmd: disconnect will raise error */
+	#define   CHM     0x40  /* sta: chained mode                */
+	#define   WSS     0x08  /* sta: wide scsi send           [W]*/
+	#define   WSR     0x01  /* sta: wide scsi received       [W]*/
+
+/*03*/  u_char    nc_scntl3;    /* cnf system clock dependent       */
+	#define   EWS     0x08  /* cmd: enable wide scsi         [W]*/
+
+/*04*/  u_char    nc_scid;	/* cnf host adapter scsi address    */
+	#define   RRE     0x40  /* r/w:e enable response to resel.  */
+	#define   SRE     0x20  /* r/w:e enable response to select  */
+
+/*05*/  u_char    nc_sxfer;	/* ### Sync speed and count         */
+
+/*06*/  u_char    nc_sdid;	/* ### Destination-ID               */
+
+/*07*/  u_char    nc_gpreg;	/* ??? IO-Pins                      */
+
+/*08*/  u_char    nc_sfbr;	/* ### First byte in phase          */
+
+/*09*/  u_char    nc_socl;
+	#define   CREQ	  0x80	/* r/w: SCSI-REQ                    */
+	#define   CACK	  0x40	/* r/w: SCSI-ACK                    */
+	#define   CBSY	  0x20	/* r/w: SCSI-BSY                    */
+	#define   CSEL	  0x10	/* r/w: SCSI-SEL                    */
+	#define   CATN	  0x08	/* r/w: SCSI-ATN                    */
+	#define   CMSG	  0x04	/* r/w: SCSI-MSG                    */
+	#define   CC_D	  0x02	/* r/w: SCSI-C_D                    */
+	#define   CI_O	  0x01	/* r/w: SCSI-I_O                    */
+
+/*0a*/  u_char    nc_ssid;
+
+/*0b*/  u_char    nc_sbcl;
+
+/*0c*/  u_char    nc_dstat;
+        #define   DFE     0x80  /* sta: dma fifo empty              */
+        #define   MDPE    0x40  /* int: master data parity error    */
+        #define   BF      0x20  /* int: script: bus fault           */
+        #define   ABRT    0x10  /* int: script: command aborted     */
+        #define   SSI     0x08  /* int: script: single step         */
+        #define   SIR     0x04  /* int: script: interrupt instruct. */
+        #define   IID     0x01  /* int: script: illegal instruct.   */
+
+/*0d*/  u_char    nc_sstat0;
+        #define   ILF     0x80  /* sta: data in SIDL register lsb   */
+        #define   ORF     0x40  /* sta: data in SODR register lsb   */
+        #define   OLF     0x20  /* sta: data in SODL register lsb   */
+        #define   AIP     0x10  /* sta: arbitration in progress     */
+        #define   LOA     0x08  /* sta: arbitration lost            */
+        #define   WOA     0x04  /* sta: arbitration won             */
+        #define   IRST    0x02  /* sta: scsi reset signal           */
+        #define   SDP     0x01  /* sta: scsi parity signal          */
+
+/*0e*/  u_char    nc_sstat1;
+	#define   FF3210  0xf0	/* sta: bytes in the scsi fifo      */
+
+/*0f*/  u_char    nc_sstat2;
+        #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   LDSC    0x02  /* sta: disconnect & reconnect      */
+
+/*10*/  u_int32    nc_dsa;	/* --> Base page                    */
+
+/*14*/  u_char    nc_istat;	/* --> Main Command and status      */
+        #define   CABRT   0x80  /* cmd: abort current operation     */
+        #define   SRST    0x40  /* mod: reset chip                  */
+        #define   SIGP    0x20  /* r/w: message from host to ncr    */
+        #define   SEM     0x10  /* r/w: message between host + ncr  */
+        #define   CON     0x08  /* sta: connected to scsi           */
+        #define   INTF    0x04  /* sta: int on the fly (reset by wr)*/
+        #define   SIP     0x02  /* sta: scsi-interrupt              */
+        #define   DIP     0x01  /* sta: host/script interrupt       */
+
+/*15*/  u_char    nc_15_;
+/*16*/	u_char	  nc_16_;
+/*17*/  u_char    nc_17_;
+
+/*18*/	u_char	  nc_ctest0;
+/*19*/  u_char    nc_ctest1;
+
+/*1a*/  u_char    nc_ctest2;
+	#define   CSIGP   0x40
+
+/*1b*/  u_char    nc_ctest3;
+	#define   CLF	  0x04	/* clear scsi fifo		    */
+
+/*1c*/  u_int32    nc_temp;	/* ### Temporary stack              */
+
+/*20*/	u_char	  nc_dfifo;
+/*21*/  u_char    nc_ctest4;
+/*22*/  u_char    nc_ctest5;
+/*23*/  u_char    nc_ctest6;
+
+/*24*/  u_int32    nc_dbc;	/* ### Byte count and command       */
+/*28*/  u_int32    nc_dnad;	/* ### Next command register        */
+/*2c*/  u_int32    nc_dsp;	/* --> Script Pointer               */
+/*30*/  u_int32    nc_dsps;	/* --> Script pointer save/opcode#2 */
+/*34*/  u_int32    nc_scratcha;  /* ??? Temporary register a         */
+
+/*38*/  u_char    nc_dmode;
+/*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 */
+
+/*3c*/  u_int32    nc_adder;
+
+/*40*/  u_short   nc_sien;	/* -->: interrupt enable            */
+/*42*/  u_short   nc_sist;	/* <--: interrupt status            */
+        #define   STO     0x0400/* sta: timeout (select)            */
+        #define   GEN     0x0200/* sta: timeout (general)           */
+        #define   HTH     0x0100/* sta: timeout (handshake)         */
+        #define   MA      0x80  /* sta: phase mismatch              */
+        #define   CMP     0x40  /* sta: arbitration complete        */
+        #define   SEL     0x20  /* sta: selected by another device  */
+        #define   RSL     0x10  /* sta: reselected by another device*/
+        #define   SGE     0x08  /* sta: gross error (over/underflow)*/
+        #define   UDC     0x04  /* sta: unexpected disconnect       */
+        #define   RST     0x02  /* sta: scsi bus reset detected     */
+        #define   PAR     0x01  /* sta: scsi parity error           */
+
+/*44*/  u_char    nc_slpar;
+/*45*/  u_char    nc_swide;
+/*46*/  u_char    nc_macntl;
+/*47*/  u_char    nc_gpcntl;
+/*48*/  u_char    nc_stime0;    /* cmd: timeout for select&handshake*/
+/*49*/  u_char    nc_stime1;    /* cmd: timeout user defined        */
+/*4a*/  u_short   nc_respid;    /* sta: Reselect-IDs                */
+
+/*4c*/  u_char    nc_stest0;
+
+/*4d*/  u_char    nc_stest1;
+
+/*4e*/  u_char    nc_stest2;
+	#define   ROF     0x40	/* reset scsi offset (after gross error!) */
+	#define   EXT     0x02  /* extended filtering                     */
+
+/*4f*/  u_char    nc_stest3;
+	#define   TE     0x80	/* c: tolerAnt enable */
+	#define   CSF    0x02	/* c: clear scsi fifo */
+
+/*50*/  u_short   nc_sidl;	/* Lowlevel: latched from scsi data */
+/*52*/  u_short   nc_52_;
+/*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    */
+/*5a*/  u_short   nc_5a_;
+/*5c*/  u_char    nc_scr0;	/* Working register B               */
+/*5d*/  u_char    nc_scr1;	/*                                  */
+/*5e*/  u_char    nc_scr2;	/*                                  */
+/*5f*/  u_char    nc_scr3;	/*                                  */
+/*60*/
+};
+
+/*-----------------------------------------------------------
+**
+**	Utility macros for the script.
+**
+**-----------------------------------------------------------
+*/
+
+#define REGJ(p,r) (offsetof(struct ncr_reg, p ## r))
+#define REG(r) REGJ (nc_, r)
+
+#ifndef TARGET_MODE
+#define TARGET_MODE 0
+#endif
+
+typedef u_int32 ncrcmd;
+
+/*-----------------------------------------------------------
+**
+**	SCSI phases
+**
+**-----------------------------------------------------------
+*/
+
+#define	SCR_DATA_OUT	0x00000000
+#define	SCR_DATA_IN	0x01000000
+#define	SCR_COMMAND	0x02000000
+#define	SCR_STATUS	0x03000000
+#define SCR_ILG_OUT	0x04000000
+#define SCR_ILG_IN	0x05000000
+#define SCR_MSG_OUT	0x06000000
+#define SCR_MSG_IN      0x07000000
+
+/*-----------------------------------------------------------
+**
+**	Data transfer via SCSI.
+**
+**-----------------------------------------------------------
+**
+**	MOVE_ABS (LEN)
+**	<<start address>>
+**
+**	MOVE_IND (LEN)
+**	<<dnad_offset>>
+**
+**	MOVE_TBL
+**	<<dnad_offset>>
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_MOVE_ABS(l) ((0x08000000 ^ (TARGET_MODE << 1ul)) | (l))
+#define SCR_MOVE_IND(l) ((0x28000000 ^ (TARGET_MODE << 1ul)) | (l))
+#define SCR_MOVE_TBL     (0x18000000 ^ (TARGET_MODE << 1ul))
+
+struct scr_tblmove {
+        u_int32  size;
+        u_int32  addr;
+};
+
+/*-----------------------------------------------------------
+**
+**	Selection
+**
+**-----------------------------------------------------------
+**
+**	SEL_ABS | SCR_ID (0..7)     [ | REL_JMP]
+**	<<alternate_address>>
+**
+**	SEL_TBL | << dnad_offset>>  [ | REL_JMP]
+**	<<alternate_address>>
+**
+**-----------------------------------------------------------
+*/
+
+#define	SCR_SEL_ABS	0x40000000
+#define	SCR_SEL_ABS_ATN	0x41000000
+#define	SCR_SEL_TBL	0x42000000
+#define	SCR_SEL_TBL_ATN	0x43000000
+
+struct scr_tblsel {
+        u_char  sel_0;
+        u_char  sel_sxfer;
+        u_char  sel_id;
+        u_char  sel_scntl3;
+};
+
+#define SCR_JMP_REL     0x04000000
+#define SCR_ID(id)	(((u_int32)(id)) << 16)
+
+/*-----------------------------------------------------------
+**
+**	Waiting for Disconnect or Reselect
+**
+**-----------------------------------------------------------
+**
+**	WAIT_DISC
+**	dummy: <<alternate_address>>
+**
+**	WAIT_RESEL
+**	<<alternate_address>>
+**
+**-----------------------------------------------------------
+*/
+
+#define	SCR_WAIT_DISC	0x48000000
+#define SCR_WAIT_RESEL  0x50000000
+
+/*-----------------------------------------------------------
+**
+**	Bit Set / Reset
+**
+**-----------------------------------------------------------
+**
+**	SET (flags {|.. })
+**
+**	CLR (flags {|.. })
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_SET(f)     (0x58000000 | (f))
+#define SCR_CLR(f)     (0x60000000 | (f))
+
+#define	SCR_CARRY	0x00000400
+#define	SCR_TRG		0x00000200
+#define	SCR_ACK		0x00000040
+#define	SCR_ATN		0x00000008
+
+
+
+
+/*-----------------------------------------------------------
+**
+**	Memory to memory move
+**
+**-----------------------------------------------------------
+**
+**	COPY (bytecount)
+**	<< source_address >>
+**	<< destination_address >>
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_COPY(n) (0xc0000000 | (n))
+
+/*-----------------------------------------------------------
+**
+**	Register move and binary operations
+**
+**-----------------------------------------------------------
+**
+**	SFBR_REG (reg, op, data)        reg  = SFBR op data
+**	<< 0 >>
+**
+**	REG_SFBR (reg, op, data)        SFBR = reg op data
+**	<< 0 >>
+**
+**	REG_REG  (reg, op, data)        reg  = reg op data
+**	<< 0 >>
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_REG_OFS(ofs) ((ofs) << 16ul)
+
+#define SCR_SFBR_REG(reg,op,data) \
+        (0x68000000 | (SCR_REG_OFS(REG(reg))) | (op) | ((data)<<8ul))
+
+#define SCR_REG_SFBR(reg,op,data) \
+        (0x70000000 | (SCR_REG_OFS(REG(reg))) | (op) | ((data)<<8ul))
+
+#define SCR_REG_REG(reg,op,data) \
+        (0x78000000 | (SCR_REG_OFS(REG(reg))) | (op) | ((data)<<8ul))
+
+
+#define      SCR_LOAD   0x00000000
+#define      SCR_SHL    0x01000000
+#define      SCR_OR     0x02000000
+#define      SCR_XOR    0x03000000
+#define      SCR_AND    0x04000000
+#define      SCR_SHR    0x05000000
+#define      SCR_ADD    0x06000000
+#define      SCR_ADDC   0x07000000
+
+/*-----------------------------------------------------------
+**
+**	FROM_REG (reg)		  reg  = SFBR
+**	<< 0 >>
+**
+**	TO_REG	 (reg)		  SFBR = reg
+**	<< 0 >>
+**
+**	LOAD_REG (reg, data)	  reg  = <data>
+**	<< 0 >>
+**
+**	LOAD_SFBR(data) 	  SFBR = <data>
+**	<< 0 >>
+**
+**-----------------------------------------------------------
+*/
+
+#define	SCR_FROM_REG(reg) \
+	SCR_REG_SFBR(reg,SCR_OR,0)
+
+#define	SCR_TO_REG(reg) \
+	SCR_SFBR_REG(reg,SCR_OR,0)
+
+#define	SCR_LOAD_REG(reg,data) \
+	SCR_REG_REG(reg,SCR_LOAD,data)
+
+#define SCR_LOAD_SFBR(data) \
+        (SCR_REG_SFBR (gpreg, SCR_LOAD, data))
+
+/*-----------------------------------------------------------
+**
+**	Waiting for Disconnect or Reselect
+**
+**-----------------------------------------------------------
+**
+**	JUMP            [ | IFTRUE/IFFALSE ( ... ) ]
+**	<<address>>
+**
+**	JUMPR           [ | IFTRUE/IFFALSE ( ... ) ]
+**	<<distance>>
+**
+**	CALL            [ | IFTRUE/IFFALSE ( ... ) ]
+**	<<address>>
+**
+**	CALLR           [ | IFTRUE/IFFALSE ( ... ) ]
+**	<<distance>>
+**
+**	RETURN          [ | IFTRUE/IFFALSE ( ... ) ]
+**	<<dummy>>
+**
+**	INT             [ | IFTRUE/IFFALSE ( ... ) ]
+**	<<ident>>
+**
+**	INT_FLY         [ | IFTRUE/IFFALSE ( ... ) ]
+**	<<ident>>
+**
+**	Conditions:
+**	     WHEN (phase)
+**	     IF   (phase)
+**	     CARRY
+**	     DATA (data, mask)
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_JUMP        0x80080000
+#define SCR_JUMPR       0x80880000
+#define SCR_CALL        0x88080000
+#define SCR_CALLR       0x88880000
+#define SCR_RETURN      0x90080000
+#define SCR_INT         0x98080000
+#define SCR_INT_FLY     0x98180000
+
+#define IFFALSE(arg)   (0x00080000 | (arg))
+#define IFTRUE(arg)    (0x00000000 | (arg))
+
+#define WHEN(phase)    (0x00030000 | (phase))
+#define IF(phase)      (0x00020000 | (phase))
+
+#define DATA(D)        (0x00040000 | ((D) & 0xff))
+#define MASK(D,M)      (0x00040000 | (((M ^ 0xff) & 0xff) << 8ul)|((D) & 0xff))
+
+#define CARRYSET       (0x00200000)
+
+/*-----------------------------------------------------------
+**
+**	SCSI  constants.
+**
+**-----------------------------------------------------------
+*/
+
+/*
+**	Messages
+*/
+
+#define	M_COMPLETE	(0x00)
+#define	M_EXTENDED	(0x01)
+#define	M_SAVE_DP	(0x02)
+#define	M_RESTORE_DP	(0x03)
+#define	M_DISCONNECT	(0x04)
+#define	M_ID_ERROR	(0x05)
+#define	M_ABORT		(0x06)
+#define	M_REJECT	(0x07)
+#define	M_NOOP		(0x08)
+#define	M_PARITY	(0x09)
+#define	M_LCOMPLETE	(0x0a)
+#define	M_FCOMPLETE	(0x0b)
+#define	M_RESET		(0x0c)
+#define	M_ABORT_TAG	(0x0d)
+#define	M_CLEAR_QUEUE	(0x0e)
+#define	M_INIT_REC	(0x0f)
+#define	M_REL_REC	(0x10)
+#define	M_TERMINATE	(0x11)
+#define	M_SIMPLE_TAG	(0x20)
+#define	M_HEAD_TAG	(0x21)
+#define	M_ORDERED_TAG	(0x22)
+#define	M_IGN_RESIDUE	(0x23)
+#define	M_IDENTIFY   	(0x80)
+
+#define	M_X_MODIFY_DP	(0x00)
+#define	M_X_SYNC_REQ	(0x01)
+#define	M_X_WIDE_REQ	(0x03)
+
+/*
+**	Status
+*/
+
+#define	S_GOOD		(0x00)
+#define	S_CHECK_COND	(0x02)
+#define	S_COND_MET	(0x04)
+#define	S_BUSY		(0x08)
+#define	S_INT		(0x10)
+#define	S_INT_COND_MET	(0x14)
+#define	S_CONFLICT	(0x18)
+#define	S_TERMINATED	(0x20)
+#define	S_QUEUE_FULL	(0x28)
+#define	S_ILLEGAL	(0xff)
+#define	S_SENSE		(0x80)
+
+/*
+ * End of ncrreg from FreeBSD
+ */
+
+#endif /* !defined HOSTS_C */
+
+#endif /* defined NCR53C8XX_H */
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/CHANGELOG linux/drivers/sound/CHANGELOG
--- v2.0.2/linux/drivers/sound/CHANGELOG	Wed Jul  3 22:05:11 1996
+++ linux/drivers/sound/CHANGELOG	Sat Jul  6 11:31:43 1996
@@ -57,7 +57,7 @@
 Since 3.5.1
 - TB Maui initialization support
 Since 3.5
-- Improved handling of playback underrunt situations.
+- Improved handling of playback underrun situations.
 
 Since 3.5-beta10
 - Bug fixing
@@ -100,14 +100,14 @@
   to James Hightower.
 
 Since 3.5-beta1
-- Bugfixes.
+- Bug fixes.
 - Full duplex audio with MAD16+CS4231 may work now. The driver configures
   SB DMA of MAD16 so that it doesn't conflict with codec's DMA channels.
   The side effect is that all 8 bit DMA channels (0,1,3) are populated in 
   duplex mode.
 
 Since 3.5-alpha9
-- Bugfixes (mostly in Jazz16 and ESS1688/688 supports).
+- Bug fixes (mostly in Jazz16 and ESS1688/688 supports).
 - Temporarily disabled recording with ESS1688/688 since it causes crash.
 - Changed audio buffer partitioning algorithm so that it selects
   smaller fragment size than earlier. This improves real time capabilities
@@ -116,7 +116,7 @@
   shorter than 4096 bytes.
 
 Since 3.5-alpha8
-- Bugfixes
+- Bug fixes
 
 Since 3.5-alpha7
 - Linux kernel compatible configuration (_EXPERIMENTAL_). Enable
@@ -135,7 +135,7 @@
 modularized version. They can be enabled by using init_trace=1 in
 the insmod command line (insmod sound init_trace=1).
 - More AIX stuff.
-- Added support for syncronizing dsp/audio devices with /dev/sequencer.
+- Added support for synchronizing dsp/audio devices with /dev/sequencer.
 - mmap() support for dsp/audio devices.
 
 Since 3.5-alpha5
@@ -148,7 +148,7 @@
   sources. Running 'setfx' is required again.
 
 Since 3.5-alpha3
-- Moved stuff from the 'setfx' program to the AudioTriX Pro driver.
+- Moved stuff from the 'setfx' program to the AudioTrix Pro driver.
 
 Since 3.5-alpha2
 - Modifications to makefile and configure.c. Unnecessary sources
@@ -159,13 +159,13 @@
 - Fixed random protection fault in gus_wave.c
 
 Since 3.5-alpha1
-- Modified to work with Linux-1.3.33 and leater
+- Modified to work with Linux-1.3.33 and later
 - Some minor changes
 
 Since 3.0.2
 - Support for CS4232 based PnP cards (AcerMagic S23 etc).
 - Full duplex support for some CS4231, CS4232 and AD1845 based cards
-(GUA MAX, AudioTrix Pro, AcerMagic S23 and many MAD16/Mozart cards
+(GUS MAX, AudioTrix Pro, AcerMagic S23 and many MAD16/Mozart cards
 having a codec mentioned above).
 - Almost fully rewritten loadable modules support.
 - Fixed some bugs.
@@ -286,13 +286,13 @@
 Since 2.2b
 - Full SB16 DSP support. 8/16 bit, mono/stereo
 - The SCO and FreeBSD versions should be in sync now. There are some
-  problems with SB16 and GUS in the freebsd versions.
+  problems with SB16 and GUS in the FreeBSD versions.
   The DMA buffer allocation of the SCO version has been polished but
   there could still be some problems. At least it hogs memory.
   The DMA channel
-  configuration method used in the sco/System is a hack.
+  configuration method used in the SCO/System is a hack.
 - Support for the MPU emulation of the SB16.
-- Some big arrays are now allocated boot time. This makes the bss segment
+- Some big arrays are now allocated boot time. This makes the BSS segment
   smaller which makes it possible to use the full driver with
   NetBSD. These arrays are not allocated if no suitable soundcard is available.
 - Fixed a bug in the compute_and_set_volume in gus_wave.c
@@ -308,7 +308,7 @@
 
 Since 2.1
 - Preliminary support for SB16. 
-  - The SB16 mixer is supported in it's native mode.
+  - The SB16 mixer is supported in its native mode.
   - Digitized voice capability up to 44.1 kHz/8 bit/mono
     (16 bit and stereo support coming in the next release).
 - Fixed some bugs in the digitized voice driver for PAS16.
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/Config.std linux/drivers/sound/Config.std
--- v2.0.2/linux/drivers/sound/Config.std	Wed Jul  3 22:05:11 1996
+++ linux/drivers/sound/Config.std	Sat Jul  6 11:31:43 1996
@@ -2,10 +2,10 @@
 # Sound driver configuration
 #
 #--------
-# There is another confic script which is compatible with rest of
+# There is another config script which is compatible with rest of
 # the kernel. It can be activated by running 'make mkscript' in this
 # directory. Please note that this is an _experimental_ feature which
-# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro, Maui).
+# doesn't work with all cards (PSS, SM Wave, AudioTrix Pro, Maui).
 #--------
 #
 $MAKE -C drivers/sound config || exit 1
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/Readme linux/drivers/sound/Readme
--- v2.0.2/linux/drivers/sound/Readme	Wed Jul  3 22:05:11 1996
+++ linux/drivers/sound/Readme	Sat Jul  6 11:31:43 1996
@@ -3,11 +3,11 @@
 
 Most up to date information about this driver is available from 
 http://www.4front-tech.com/usslite or http://personal.eunet.fi/pp/voxware
-(european mirror).
+(European mirror).
 
 
 
-Please read the SOUND-HOWTO (available from sunsite.unc.edu and other Linux ftp 
+Please read the SOUND-HOWTO (available from sunsite.unc.edu and other Linux FTP 
 sites). It gives instructions about using sound with Linux. It's bit out of
 date but still very useful. Information about bug fixes and such things
 is available from the web page (see below).
@@ -23,7 +23,7 @@
 Linux versions later than 2.0.x.
 
 Packages "snd-util-3.5.tar.gz" and "snd-data-0.1.tar.Z"
-contain usefull utilities to be used with this driver.
+contain useful utilities to be used with this driver.
 See http://www.4front-tech.com/usslite/getting.html for
 download instructions.
 
@@ -42,7 +42,7 @@
 ------------
 
 This driver contains code by several contributors. In addition several other
-persons have given usefull suggestions. The following is a list of major
+persons have given useful suggestions. The following is a list of major
 contributors. (I could have forgotten some names.)
 
 	Craig Metz	1/2 of the PAS16 Mixer and PCM support
@@ -54,7 +54,7 @@
 	Andy Warner	ISC port
 	Jim Lowe,
 	Amancio Hasty Jr	FreeBSD/NetBSD port
-	Anders Baekgaard 	Bughunting and valuable suggestions.
+	Anders Baekgaard 	Bug hunting and valuable suggestions.
 	Joerg Schubert	SB16 DSP support (initial version).
 	Andrew Robinson Improvements to the GUS driver
 	Megens SA	MIDI recording for SB and SB Pro (initial version).
@@ -76,7 +76,7 @@
 	
 	Please look at lowlevel/README for more contributors.
 
-There are propably many other names missing. If you have sent me some
+There are probably many other names missing. If you have sent me some
 patches and your name is not in the above list, please inform me.
 
 Sponsors etc.
@@ -125,7 +125,7 @@
 at /var/adm/messages for more verbose error message.
 
 
-In general the easiest way to diagnoze problems is to do "cat /dev/sndstat".
+In general the easiest way to diagnose problems is to do "cat /dev/sndstat".
 
 If you get an error message, there are some problems with the driver setup:
 
@@ -133,7 +133,7 @@
 	the sound driver are missing. Use the script at the end of
 	linux/drivers/sound/Readme.linux to create them.
 
-	- "No such device" telss that the sound driver is not in the kernel.
+	- "No such device" tells that the sound driver is not in the kernel.
 	You have to reconfigure and recompile the kernel to have the sound
 	driver. Compiling the driver doesn't help alone. You have to boot
 	with the newly compiled one before the driver becomes active.
@@ -148,7 +148,7 @@
 	this particular device. For example /dev/audio and /dev/dsp will not
 	work if "digitized voice support" was not enabled during "make config".
 	
-	- "Device or resource busy". Propably the IRQ (or DMA) channel 
+	- "Device or resource busy". Probably the IRQ (or DMA) channel 
 	required by the soundcard is in use by some other device/driver.
 
 	- "I/O error". Almost certainly (99%) it's an IRQ or DMA conflict.
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/Readme.cards linux/drivers/sound/Readme.cards
--- v2.0.2/linux/drivers/sound/Readme.cards	Wed Jul  3 22:05:11 1996
+++ linux/drivers/sound/Readme.cards	Sat Jul  6 11:31:43 1996
@@ -16,8 +16,8 @@
 		work with them.
 
 		When using make xconfig and/or make menuconfig, you should
-		carefully check each sound configuration option (particularily
-		"Support for /dev/dsp and /dev/ausio").
+		carefully check each sound configuration option (particularly
+		"Support for /dev/dsp and /dev/audio").
 
 Cards that are not (fully) supported by this driver
 ---------------------------------------------------
@@ -29,9 +29,9 @@
 mail me and ask about these cards. The unsupported cards are:
 
 	- All PnP soundcards (SB PnP, GUS PnP, Soundscape PnP etc.)
-		Schecule for availability of PnP soundcard support in
+		Schedule for availability of PnP soundcard support in
 		USS/Lite depends on progress made by kernel PnP team
-		(propably in Linux 2.1.xx versions). With Linux 2.0.x
+		(probably in Linux 2.1.xx versions). With Linux 2.0.x
 		versions there are two ways to get PnP soundcards to work:
 	 	- Use isapnptools, DOS, Win95 or PnP aware BIOS to wake up the
 		card before starting the sound driver. See "Configuring PnP 
@@ -42,7 +42,7 @@
 		(Version 3.6 or 3.7. Depends on how fast I get
 		suitable documents for Mwave).
 	- Emu8k (SB 32/AWE)
-		(Propably not _before_ summer 97. I know the unofficial
+		(Probably not _before_ summer 97. I know the unofficial
 		AWE programmers guide so don't send me more copies of it).
 	- Diamond Edge 3D
 		(ASAP. In practice this may take relatively long time).
@@ -69,8 +69,8 @@
 soft configuring their I/O, IRQ, DMA and shared memory resources.
 Currently at least cards made by Creative Technology (SB32 and SB32AWE
 PnP), Gravis (GUS PnP and GUS PnP Pro), Ensoniq (Soundscape PnP) and
-Aztech (some Sound Galazy models) use PnP technology. The CS4232 audio
-chip by Crystal Semiconductor (Intel Atlantis, HP Pavillon and many other
+Aztech (some Sound Galaxy models) use PnP technology. The CS4232 audio
+chip by Crystal Semiconductor (Intel Atlantis, HP Pavilion and many other
 motherboards) is also based on PnP technology but there is a "native" driver
 available for it (see information about CS4232 later in this document).
 
@@ -93,7 +93,7 @@
 your card for more info.
 
 Windows 95 could work as well as DOS but running loadlin may be somehow 
-difficult. Propably you should "shut down" your machine to MS-DOS mode
+difficult. Probably you should "shut down" your machine to MS-DOS mode
 before running it.
 
 Some machines have BIOS utility for setting PnP resources. This is a good
@@ -238,7 +238,7 @@
 	interface chip performs address decoding for the other chips.
 	NOTE! Tropez Plus is not MAD16 but CS4232 based.
 
-Audio Excell DSP16 
+Audio Excel DSP16 
 	Support for this card was written by Riccardo Faccetti
 	(riccardo@cdc8g5.cdc.polimi.it). See aedsp16.c for more info.
 	(This driver is not functional in version 3.5 of this driver. A
@@ -275,14 +275,14 @@
 Latest cards are fully software configurable or they are PnP ISA
 compatible. There are no jumpers on the board.
 
-The driver handles software configurable cards automaticly. Just configure
+The driver handles software configurable cards automatically. Just configure
 the driver to use I/O, IRQ and DMA settings which are known to work.
 You could usually use the same values than with DOS and/or Windows.
 Using different settings is possible but not recommended since it may cause
 some trouble (for example when warm booting from an OS to another or
 when installing new hardware to the machine).
 
-Sound driver sets the soft configurable parameters of the card automaticly
+Sound driver sets the soft configurable parameters of the card automatically
 during boot. Usually you don't need to run any extra initialization
 programs when booting Linux but there are some exceptions. See the
 card specific instructions (below) for more info.
@@ -379,12 +379,12 @@
 since using the default _doesn't_ guarantee anything.
 
 Note also that all questions may not be asked. The configuration program
-may disable some questions dependig on the earlier choices. It may also
-select some options automaticly as well.
+may disable some questions depending on the earlier choices. It may also
+select some options automatically as well.
 
   "ProAudioSpectrum 16 support",
 	- Answer 'y'_ONLY_ if you have a Pro Audio Spectrum _16_,
-	  ProAudio Studio 16 or Logitech SoundMan 16 (be sure that
+	  Pro Audio Studio 16 or Logitech SoundMan 16 (be sure that
 	  you read the above list correctly). Don't answer 'y' if you
 	  have some other card made by Media Vision or Logitech since they
 	  are not PAS16 compatible.
@@ -392,7 +392,7 @@
 	  if you want to use the SB emulation of PAS16. It's also possible to
    	  the emulation if you want to use a true SB card together with PAS16
 	  (there is another question about this that is asked later).
-  "SoundBlaster support",
+  "Sound Blaster support",
 	- Answer 'y' if you have an original SB card made by Creative Labs
 	  or a full 100% hardware compatible clone (like Thunderboard or
 	  SM Games). If your card was in the list of supported cards (above),
@@ -448,7 +448,7 @@
 	  conflict.
   "Ensoniq Soundscape support",
 	- Answer 'y' if you have a soundcard based on the Ensoniq SoundScape
-	  chipset. Suach cards are being manufactured at least by Ensoniq,
+	  chipset. Such cards are being manufactured at least by Ensoniq,
 	  Spea and Reveal (note that Reveal makes other cards also).
   "MediaTrix AudioTrix Pro support",
 	- Answer 'y' if you have the AudioTrix Pro.
@@ -460,7 +460,7 @@
 	  cards made by known manufacturers such as Turtle Beach (Tropez),
 	  Reveal (some models) and Diamond (some recent models).
   "Support for TB Maui"
-	- This enables TB Maui spesific initialization. Works with TB Maui
+	- This enables TB Maui specific initialization. Works with TB Maui
 	and TB Tropez (may not work with Tropez Plus).
 
   "Audio Excel DSP 16 initialization support",
@@ -505,7 +505,7 @@
 different values could cause some problems when switching between
 different operating systems.
 
-SoundBlasters (the original ones by Creative)
+Sound Blasters (the original ones by Creative)
 ---------------------------------------------
 
 It's possible to configure these cards to use different I/O, IRQ and
@@ -543,7 +543,7 @@
 was listed in the beginning of this file. In this case you should follow
 instructions for your card later in this file.
 
-For other not fully SB clones yoy may try initialization using DOS in
+For other not fully SB clones you may try initialization using DOS in
 the following way:
 
 	- Boot DOS so that the card specific driver gets run.
@@ -685,10 +685,10 @@
 
 Configuring ATP is little bit tricky since it uses so many I/O, IRQ and
 DMA numbers. Using the same values than with DOS/Win is a good idea. Don't
-attemp to use the same IRQ or DMA channels twice.
+attempt to use the same IRQ or DMA channels twice.
 
 The SB mode of ATP is implemented so the the ATP driver just enables SB
-in the proper address. The SB driver handles the rest. Yoy have to configure
+in the proper address. The SB driver handles the rest. You have to configure
 both the SB driver and the SB mode of ATP to use the same IRQ, DMA and I/O
 settings.
 
@@ -720,7 +720,7 @@
 !!!!!	    point to /dev/dsp1.						!!!!
 !!!!!                                                                   !!!!
 !!!!!	    This is not required with USS versions 3.5-beta6 and later	!!!!
-!!!!!	    since there is now just one audio device file. Pleace 	!!!!
+!!!!!	    since there is now just one audio device file. Please 	!!!!
 !!!!!	    change /dev/dsp to point back to /dev/dsp0 if you are	!!!!
 !!!!!	    upgrading from an earlier driver version using		!!!!
 !!!!!	    (cd /dev;rm dsp;ln -s dsp0 dsp).				!!!!
@@ -730,7 +730,7 @@
 The configuration program asks one DMA channel and two interrupts. One IRQ
 and one DMA is used by the MSS codec. The second IRQ is required for the
 MPU401 mode (you have to use different IRQs for both purposes).
-There were earlier two DMA channels for soundscape but the current driver
+There were earlier two DMA channels for SoundScape but the current driver
 version requires just one.
 
 The SoundScape card has a Motorola microcontroller which must initialized
@@ -795,7 +795,7 @@
 
 If you have a MAD16 card which have an OPL4 (FM + Wave table) synthesizer
 chip (_not_ an OPL3), you have to append a line containing #define MAD16_OPL4
-to the file linux/dirvers/sound/local.h (after running make config).
+to the file linux/drivers/sound/local.h (after running make config).
 
 MAD16 cards having a CS4231 codec support full duplex mode. This mode
 can be enabled by configuring the card to use two DMA channels. Possible
@@ -814,12 +814,12 @@
 problems if you have another MPU401 compatible card. In this case you must
 give address of the Jazz16 based MPU401 interface when the config
 program prompts for the MPU401 information. Then look at the MPU401
-spesific section for instructions about configuring more than one MPU401 cards.
+specific section for instructions about configuring more than one MPU401 cards.
 
 Logitech Soundman Wave
 ----------------------
 
-Read the above MV Jazz spesific instructions first.
+Read the above MV Jazz specific instructions first.
 
 The Logitech SoundMan Wave (don't confuse with the SM16 or SM Games) is
 a MV Jazz based card which has an additional OPL4 based wave table
@@ -839,7 +839,7 @@
 
 NOTE!	Don't answer 'y' when the driver asks about SM Games support
 	(the next question after the MIDI0001.BIN name). However
-	aneswering 'y' doesn't cause damage your computer so don't panic. 
+	answering 'y' doesn't cause damage your computer so don't panic. 
 
 Sound Galaxies
 --------------
@@ -850,7 +850,7 @@
 
 The older 16 bit cards (SG Pro16, SG NX Pro16, Nova and Lyra) have
 an EEPROM chip for storing the configuration data. There is a microcontroller
-which initializes the card to match the EEPROM settigs when the machine
+which initializes the card to match the EEPROM settings when the machine
 is powered on. These cards actually behave just like they have jumpers
 for all of the settings. Configure driver for MSS, MPU, SB/SB Pro  and OPL3 
 supports with these cards. 
@@ -868,7 +868,7 @@
 Support for these two ESS chips is embedded in the SB driver.
 Configure these cards just like SB. Enable the 'SB MPU401 MIDI port'
 if you want to use MIDI features of ES1688. ES688 doesn't have MPU mode
-so you don't need to enable it (the driver uses normal SB MIDI automaticly
+so you don't need to enable it (the driver uses normal SB MIDI automatically
 with ES688).
 
 NOTE! ESS cards are not compatible with MSS/WSS.
@@ -969,19 +969,19 @@
 Please check which version of sound driver you are using before 
 complaining that your card is not supported. It's possible that you are 
 using a driver version which was released months before your card was
-introduced. Driver's release date is listed after it's version number
+introduced. Driver's release date is listed after its version number
 in "cat /dev/sndstat" printout and in file linux/drivers/sound/soundvers.h.
 
 First of all. There is an easy way to make most soundcards to work
 with Linux. Just use the DOS based driver to initialize the card
 to a _known_ state. Then use loadlin.exe to boot Linux. If Linux is configured
-to use the sama I/O, IRQ and DMA numbers than DOS, the card could work.
+to use the same I/O, IRQ and DMA numbers than DOS, the card could work.
 (ctrl-alt-del can be used in place of loadlin.exe but it doesn't work with
 new motherboards). This method works also with all/most PnP soundcards.
 
 Don't get fooled with SB compatibility. Most cards are compatible with
 SB but that may require a TSR which is not possible with Linux. If
-the card is compatible with MSS, it's a better choise. Some cards
+the card is compatible with MSS, it's a better choice. Some cards
 don't work in the SB and MSS modes at the same time.
 
 Then there are cards which are no longer manufactured and/or which
@@ -990,7 +990,7 @@
 Adding support for a new card requires much work and increases time
 required in maintaining the driver (some changes need to be done
 to all low level drivers and be tested too, maybe with multiple
-operating systems). For this reason I have made a desicion to not support
+operating systems). For this reason I have made a decision to not support
 obsolete cards. It's possible that someone else makes a separately 
 distributed driver (diffs) for the card. Version v3.6 will be much more
 modular so making separately distributed drivers will be easier with it.
@@ -1004,12 +1004,12 @@
 released technical details of the card. Do this before contacting me. I
 can only answer 'no' if there are no programming information available.
 
-I have made decicion to not accept code based on reverse engineering
+I have made decision to not accept code based on reverse engineering
 to the driver. There are three main reasons: First I don't want to break
 relationships to sound card manufacturers. The second reason is that
-maintaining and supporting a driver withoun any specs will be a pain.
+maintaining and supporting a driver without any specs will be a pain.
 The third reason is that companies have freedom to refuse selling their
-products to other than Windows useres.
+products to other than Windows users.
 
 Some companies don't give low level technical information about their
 products to public or at least their require signing a NDA. It's not
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/Readme.linux linux/drivers/sound/Readme.linux
--- v2.0.2/linux/drivers/sound/Readme.linux	Wed Jul  3 22:05:11 1996
+++ linux/drivers/sound/Readme.linux	Sat Jul  6 11:31:43 1996
@@ -19,7 +19,7 @@
   sources). Remove old version of linux/drivers/sound directory before
   installing new files.
 
-- To build the device files you need to run the enclosed shell scrip 
+- To build the device files you need to run the enclosed shell script 
   (see below). You need to do this only when installing sound driver
   first time or when upgrading to much recent version than the earlier
   one.
@@ -27,13 +27,13 @@
 - Configure and compile Linux as normally (remember to include the
   sound support during "make config"). Please refer to kernel documentation
   for instructions about configuring and compiling kernel. File Readme.cards
-  contains card spesific instructions for configuring this driver for
+  contains card specific instructions for configuring this driver for
   use with various soundcards.
 
 Boot time configuration (using lilo and insmod) 
 -----------------------------------------------
 
-This information has been removed. Too many users did't believe
+This information has been removed. Too many users didn't believe
 that it's really not necessary to use this method. Please look at
 Readme of sound driver version 3.0.1 if you still want to use this method.
 
@@ -46,7 +46,7 @@
 
 	cat /dev/sndstat 
 
-and look at the output. It should display some usefull info about the
+and look at the output. It should display some useful info about the
 driver configuration. If there is no /dev/sndstat 
 (/dev/sndstat: No such file or directory), ensure that you have executed the
 soundinstall script (at the end of this file).
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/Readme.modules linux/drivers/sound/Readme.modules
--- v2.0.2/linux/drivers/sound/Readme.modules	Wed Jul  3 22:05:11 1996
+++ linux/drivers/sound/Readme.modules	Sat Jul  6 11:31:43 1996
@@ -45,10 +45,10 @@
 
 	insmod sound dma_buffsize=32768
 
-Minimum buffer size is 4096 and the maximum depends on the DMA channe. 
+Minimum buffer size is 4096 and the maximum depends on the DMA channel. 
 For 8 bit channels (0 to 3) the limit is 64k and for 16 bit ones (5 to 7)
-it's 128k. Driver selects a suitable buffer size automaticly in case
-you try to spesify an invalid size.
+it's 128k. Driver selects a suitable buffer size automatically in case
+you try to specify an invalid size.
 
 Q: What is the right DMA buffer size?
 
@@ -58,17 +58,17 @@
 recording to hard disk is likely to require large buffers.
 
 Very small buffers are sufficient when you are just playing 8kHz audio files 
-on an empty P133 system. Using a 128k byffer just wastes 120k (or 250k)
+on an empty P133 system. Using a 128k buffer just wastes 120k (or 250k)
 of valuable physical RAM memory. 
 
-The right buffer sice can be easily found by making some experiments
+The right buffer size can be easily found by making some experiments
 with the dma_buffsize= parameter. I use usually 16k buffers on a DX4/100 system
 and 64k on an old 386 system. 
 
 NOTE!	DMA buffers are used only by /dev/audio# and /dev/dsp# devices.
 	Other device files don't use them but there are two exceptions:
 	GUS driver uses DMA buffers when loading samples to the card.
-	Ensoniq SoundScape driver uses them when doanloading the microcode
+	Ensoniq SoundScape driver uses them when downloading the microcode
 	file (sndscape.co[012]) to the card. Using large buffers doesn't
 	increase performance in these cases.
 
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/Readme.v30 linux/drivers/sound/Readme.v30
--- v2.0.2/linux/drivers/sound/Readme.v30	Wed Jul  3 22:05:12 1996
+++ linux/drivers/sound/Readme.v30	Sat Jul  6 11:31:43 1996
@@ -18,7 +18,7 @@
 /dev/midi##
 -----------
 
-This interface should be usefull for applications like MIDI sysex librarians.
+This interface should be useful for applications like MIDI sysex librarians.
 There are (currently) no timing features so making music could be impossible.
 
 There are as many /dev/midi## devices as there are MIDI ports in the system. 
@@ -53,7 +53,7 @@
 If this ioctl is called with mode=1, the interface is put to the intelligent
 (coprocessor) mode. NOTE! The MIDI port will be reset when this ioctl is called.
 It could have some strange effects if not called immediately after open. This
-vall returns EINVAL if the midi port doesn't support the MPU-401 intelligent
+call returns EINVAL if the midi port doesn't support the MPU-401 intelligent
 mode.
 
 ioctl(fd, SNDCTL_MIDI_MPUCMD, &cmdstruct) is valid only if the MIDI port
@@ -81,10 +81,10 @@
 	data		Buffer for the command arguments and returned
 			data.
 
-Be extremely carefull with the nr_args and nr_returns fields. They
+Be extremely careful with the nr_args and nr_returns fields. They
 must match the command. An incorrect value will put the card and
 the driver out of sync. Refer to the MPU-401/MQX-32M documentation for further
-datails.
+details.
 
 
 
@@ -99,7 +99,7 @@
 /dev/sequencer. Both kind of devices are accessed using the SEQ_START_NOTE()
 like macros. The voice number parameters of the API macros have been redefined
 to denote MIDI channels. This means that the driver allocates voices for
-the channels automaticly (this is a responsibility/right of an application
+the channels automatically (this is a responsibility/right of an application
 with /dev/sequencer). The result is that a SEQ_START_NOTE() macro has
 similar effects for a synth channel than on a MIDI port. This kind of
 solution provides better device independence than the /dev/sequencer. The
@@ -116,15 +116,15 @@
 
 - The new interface is used much like the ordinary /dev/sequencer. The
 event format is new so you have to use the API macros defined in the 
-sys/soundcard.h. The interface is will propably change before the final 3.0
+sys/soundcard.h. The interface is will probably change before the final 3.0
 release but using the API macros should ensure compatibility in source level.
 The new event format is not recognized by version 2.X so don't try to 
 distribute binaries compiled with soundcard.h of v3.X.
 
-- The basic API useage is similar to the current one. There are some new
+- The basic API usage is similar to the current one. There are some new
 macros but the older ones should work as earlier. The most important
 incompatibility is that the /dev/sequencer2 driver allocates voices itself.
-The other one is that the application must send SEQ_START_TIMER() as it's
+The other one is that the application must send SEQ_START_TIMER() as its
 first event. Otherwise the timer is not started and the application waits
 infinitely.
 
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
--- v2.0.2/linux/drivers/sound/ad1848.c	Wed Jul  3 22:05:12 1996
+++ linux/drivers/sound/ad1848.c	Sat Jul  6 11:31:42 1996
@@ -523,8 +523,8 @@
   ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
 
   /*
-     * The sampling speed is encoded in the least significant nible of I8. The
-     * LSB selects the clock source (0=24.576 MHz, 1=16.9344 Mhz) and other
+     * The sampling speed is encoded in the least significant nibble of I8. The
+     * LSB selects the clock source (0=24.576 MHz, 1=16.9344 MHz) and other
      * three bits select the divisor (indirectly):
      *
      * The available speeds are in the following table. Keep the speeds in
@@ -961,7 +961,7 @@
 
   ad_write (devc, 8, fs);
   /*
-   * Write to I8 starts resyncronization. Wait until it completes.
+   * Write to I8 starts resynchronization. Wait until it completes.
    */
   timeout = 10000;
   while (timeout > 0 && inb (devc->base) == 0x80)
@@ -975,7 +975,7 @@
       ad_write (devc, 28, fs);
 
       /*
-         * Write to I28 starts resyncronization. Wait until it completes.
+         * Write to I28 starts resynchronization. Wait until it completes.
        */
       timeout = 10000;
       while (timeout > 0 && inb (devc->base) == 0x80)
@@ -1183,7 +1183,7 @@
      * Check that the I/O address is in use.
      *
      * The bit 0x80 of the base I/O port is known to be 0 after the
-     * chip has performed it's power on initialization. Just assume
+     * chip has performed its power on initialization. Just assume
      * this has happened before the OS is starting.
      *
      * If the I/O address is unused, it typically returns 0xff.
@@ -1481,7 +1481,7 @@
 	ad_write (devc, 27, ad_read (devc, 27) | 0x08);		/* Alternate freq select enabled */
 
       if (devc->model == MD_IWAVE)
-	{			/* Some magic Interwave spesific initialization */
+	{			/* Some magic Interwave specific initialization */
 	  ad_write (devc, 12, 0x6c);	/* Select codec mode 3 */
 	  ad_write (devc, 17, 0xc2);	/* Alternate feature enable */
 	}
@@ -1537,8 +1537,8 @@
 
 	  devc->timer_ticks = 0;
 
-	  ad_write (devc, 21, 0x00);	/* Timer msb */
-	  ad_write (devc, 20, 0x10);	/* Timer lsb */
+	  ad_write (devc, 21, 0x00);	/* Timer MSB */
+	  ad_write (devc, 20, 0x10);	/* Timer LSB */
 
 	  ad_write (devc, 16, tmp | 0x40);	/* Enable timer */
 	  for (x = 0; x < 100000 && devc->timer_ticks == 0; x++);
@@ -1618,7 +1618,7 @@
 	}
     }
   else
-    printk ("ad1848: Can't find device to be undoaded. Base=%x\n",
+    printk ("ad1848: Can't find device to be unloaded. Base=%x\n",
 	    io_base);
 }
 
@@ -1816,7 +1816,7 @@
 /*
  * I/O port 0xc45 FM Address Decode/MSS ID Register.
  *
- * bank=0, bits 0xfe:   FM synthesis Decode Comare bits 7:1 (default=0x88)
+ * bank=0, bits 0xfe:   FM synthesis Decode Compare bits 7:1 (default=0x88)
  * bank=0, bit 0x01:    SBIC Power Control Bit
  *                      0x00 = Powered up
  *                      0x01 = Powered down
@@ -1880,7 +1880,7 @@
 /*
  * I/O port 0xc47 FM Address Decode Register.
  *
- * bank=0, bits 0xff:   Decode enble selection for various FM address bits
+ * bank=0, bits 0xff:   Decode enable selection for various FM address bits
  * bank=1, bits 0xff:   Reserved
  */
 
@@ -2152,7 +2152,7 @@
 {
   unsigned long   flags;
   ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
-  unsigned long   xtal_nsecs;	/* nanoseconds per xtal oscillaror tick */
+  unsigned long   xtal_nsecs;	/* nanoseconds per xtal oscillator tick */
   unsigned long   divider;
 
   save_flags (flags);
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/aedsp16.c linux/drivers/sound/aedsp16.c
--- v2.0.2/linux/drivers/sound/aedsp16.c	Wed Jul  3 22:05:12 1996
+++ linux/drivers/sound/aedsp16.c	Sat Jul  6 11:31:42 1996
@@ -70,7 +70,7 @@
 
    The Audio Excel DSP 16 Sound Card emulates both SBPRO and MSS;
    the voxware sound driver can be configured for SBPRO and MSS cards
-   at the same time, but the aedsp16 can't be two cards!!
+   at the same time, but the AEDSP16 can't be two cards!!
    When we configure it, we have to choose the SBPRO or the MSS emulation
    for AEDSP16. We also can install a *REAL* card of the other type
    (see [1], not tested but I can't see any reason for it to fail).
@@ -143,7 +143,7 @@
    this way.
 
    Should be interesting eventually write down a new ioctl for the
-   aedsp16, to let the suser() change the irq/dma/mirq on the fly.
+   AEDSP16, to let the suser() change the irq/dma/mirq on the fly.
    The thing is not trivial.
    In the real world, there's no need to have such an ioctl because
    when we configure the kernel for compile, we can choose the config
@@ -154,7 +154,7 @@
    the code to do it.
 
    More integration with voxware, using voxware low level routines to
-   read-write dsp is not possible because you may want to have MSS
+   read-write DSP is not possible because you may want to have MSS
    support and in that case we can not rely on the functions included
    in sb_dsp.c to control 0x2yy I/O ports. I will continue to use my
    own I/O functions.
@@ -170,20 +170,20 @@
    I think the request regions should be done this way:
 
    if (check_region(...))
-   return ERR; // I/O region alredy reserved
+   return ERR; // I/O region already reserved
    device_probe(...);
    device_attach(...);
    request_region(...); // reserve only when we are sure all is okay
 
    Request the 2x0h region in any case if we are using this card.
 
-   NOTE: the "(sbpro)" string with which we are requesting the aedsp16 region
-   (see code) does not mean necessarly that we are emulating sbpro.
-   It mean that the region is the sbpro I/O ports region. We use this
+   NOTE: the "(SBPro)" string with which we are requesting the AEDSP16 region
+   (see code) does not mean necessarily that we are emulating SBPro.
+   It mean that the region is the SBPro I/O ports region. We use this
    region to access the control registers of the card, and if emulating
-   sbpro, I/O sbpro registers too. If we are emulating MSS, the sbpro
-   registers are not used, in no way, to emulate an sbpro: they are
-   used only for configuration pourposes.
+   SBPro, I/O SBPro registers too. If we are emulating MSS, the SBPro
+   registers are not used, in no way, to emulate an SBPro: they are
+   used only for configuration purposes.
 
    Someone pointed out that should be possible use both the SBPRO and MSS
    modes because the sound card have all the two chipsets, supposing that
@@ -191,7 +191,7 @@
    modes work together, but, for some reason unknown to me, without success.
 
    I think all the soft-config only cards have an init sequence similar to
-   this. If you have a card that is not an aedsp16, you can try to start
+   this. If you have a card that is not an AEDSP16, you can try to start
    with this module changing it (mainly in the CMD? I think) to fit your
    needs.
 
@@ -202,7 +202,7 @@
    v0.2 (ALPHA)
    - Cleanups.
    - Integrated with Linux voxware v 2.90-2 kernel sound driver.
-   - SoundBlaster Pro mode configuration.
+   - Sound Blaster Pro mode configuration.
    - Microsoft Sound System mode configuration.
    - MPU-401 mode configuration.
    v0.3 (ALPHA)
@@ -216,16 +216,16 @@
    - Added the code to request_region at device init (should go in
    the main body of voxware).
    v0.4 (BETA)
-   - Better configure.c patch for aedsp16 configuration (better
+   - Better configure.c patch for AEDSP16 configuration (better
    logic of inclusion of AEDSP16 support)
    - Modified the conditional compilation to better support more than
    one sound card of the emulated type (read the NOTES above)
    - Moved the sb init routine from the attach to the very first
    probe in sb_card.c
-   - Rearrangemens and cleanups
+   - Rearrangements and cleanups
    - Wiped out some unnecessary code and variables: this is kernel
    code so it is better save some TEXT and DATA
-   - Fixed the request_region code. We must allocate the aedsp16 (sbpro)
+   - Fixed the request_region code. We must allocate the AEDSP16 (SBPro)
    I/O ports in any case because they are used to access the DSP
    configuration registers and we can not allow anyone to get them.
    v0.5
@@ -263,7 +263,7 @@
 #define CMD6 0x8c		/* Enable Microsoft Sound System mode   */
 
 /*
- * Offsets of AEDSP16 DSP I/O ports. The offest is added to portbase
+ * Offsets of AEDSP16 DSP I/O ports. The offset is added to portbase
  * to have the actual I/O port.
  * Register permissions are:
  * (wo) == Write Only
@@ -431,7 +431,7 @@
     }
   while (loop--);
 
-  printk ("[aedsp16] DSP Command (0x%x) timeout.\n", cmd);
+  printk ("[AEDSP16] DSP Command (0x%x) timeout.\n", cmd);
   return -1;
 }
 
@@ -443,7 +443,7 @@
 
   if (WriteDSPCommand (port, CMD6))
     {
-      printk ("[aedsp16] CMD 0x%x: failed!\n", CMD6);
+      printk ("[AEDSP16] CMD 0x%x: failed!\n", CMD6);
       return -1;
     }
 
@@ -461,7 +461,7 @@
     {
       if (WriteDSPCommand (portbase, CMD3))
 	{
-	  printk ("[aedsp16] CMD 0x%x: failed!\n", CMD3);
+	  printk ("[AEDSP16] CMD 0x%x: failed!\n", CMD3);
 	  return -1;
 	}
 
@@ -473,32 +473,32 @@
 #if defined(THIS_SHOULD_GO_AWAY)
   if (CheckDSPOkay (port))
     {
-      printk ("[aedsp16]     CheckDSPOkay: failed\n");
+      printk ("[AEDSP16]     CheckDSPOkay: failed\n");
       return -1;
     }
 #else
   if (ReadData (port) == -1)
     {
-      printk ("[aedsp16] ReadData after CMD 0x%x: failed\n", CMD3);
+      printk ("[AEDSP16] ReadData after CMD 0x%x: failed\n", CMD3);
       return -1;
     }
 #endif
 
   if (WriteDSPCommand (portbase, CMD4))
     {
-      printk ("[aedsp16] CMD 0x%x: failed!\n", CMD4);
+      printk ("[AEDSP16] CMD 0x%x: failed!\n", CMD4);
       return -1;
     }
 
   if (WriteDSPCommand (portbase, CMD5))
     {
-      printk ("[aedsp16] CMD 0x%x: failed!\n", CMD5);
+      printk ("[AEDSP16] CMD 0x%x: failed!\n", CMD5);
       return -1;
     }
 
   if (WriteDSPCommand (portbase, oredparams))
     {
-      printk ("[aedsp16] Initialization of (M)IRQ and DMA: failed!\n");
+      printk ("[AEDSP16] Initialization of (M)IRQ and DMA: failed!\n");
       return -1;
     }
   return 0;
@@ -516,7 +516,7 @@
       if ((ret = ReadData (port)) == -1)
 	return -1;
       /*
-         * We alredy know how many int are stored (2), so we know when the
+         * We already know how many int are stored (2), so we know when the
          * string is finished.
        */
       ver[len++] = ret;
@@ -536,7 +536,7 @@
     {
       if ((ret = ReadData (port)) == -1)
 	/*
-	   * If no more data availabe, return to the caller, no error if len>0.
+	   * If no more data available, return to the caller, no error if len>0.
 	   * We have no other way to know when the string is finished.
 	 */
 	return (len ? 0 : -1);
@@ -577,27 +577,27 @@
 
   if (ResetBoard (portbase))
     {
-      printk ("[aedsp16] ResetBoard: failed!\n");
+      printk ("[AEDSP16] ResetBoard: failed!\n");
       return -1;
     }
 
 #if defined(THIS_SHOULD_GO_AWAY)
   if (CheckDSPOkay (portbase))
     {
-      printk ("[aedsp16] CheckDSPOkay: failed!\n");
+      printk ("[AEDSP16] CheckDSPOkay: failed!\n");
       return -1;
     }
 #endif
 
   if (WriteDSPCommand (portbase, CMD1))
     {
-      printk ("[aedsp16] CMD 0x%x: failed!\n", CMD1);
+      printk ("[AEDSP16] CMD 0x%x: failed!\n", CMD1);
       return -1;
     }
 
   if (GetCardName (portbase))
     {
-      printk ("[aedsp16] GetCardName: failed!\n");
+      printk ("[AEDSP16] GetCardName: failed!\n");
       return -1;
     }
 
@@ -606,23 +606,23 @@
      * if we have something different, we have to be warned.
    */
   if (strcmp ("SC-6000", AudioExcelName))
-    printk ("[aedsp16] Warning: non SC-6000 audio card!\n");
+    printk ("[AEDSP16] Warning: non SC-6000 audio card!\n");
 
   if (WriteDSPCommand (portbase, CMD2))
     {
-      printk ("[aedsp16] CMD 0x%x: failed!\n", CMD2);
+      printk ("[AEDSP16] CMD 0x%x: failed!\n", CMD2);
       return -1;
     }
 
   if (GetCardVersion (portbase))
     {
-      printk ("[aedsp16] GetCardVersion: failed!\n");
+      printk ("[AEDSP16] GetCardVersion: failed!\n");
       return -1;
     }
 
   if (SetUpBoard (portbase))
     {
-      printk ("[aedsp16] SetUpBoard: failed!\n");
+      printk ("[AEDSP16] SetUpBoard: failed!\n");
       return -1;
     }
 
@@ -630,7 +630,7 @@
     {
       if (InitMSS (portbase))
 	{
-	  printk ("[aedsp16] Can't initialize Microsoft Sound System mode.\n");
+	  printk ("[AEDSP16] Can't initialize Microsoft Sound System mode.\n");
 	  return -1;
 	}
     }
@@ -666,7 +666,7 @@
 InitAEDSP16_SBPRO (struct address_info *hw_config)
 {
   /*
-     * If the card is alredy init'ed MSS, we can not init it to SBPRO too
+     * If the card is already init'ed MSS, we can not init it to SBPRO too
      * because the board can not emulate simultaneously MSS and SBPRO.
    */
   if (ae_init & INIT_MSS)
@@ -683,7 +683,7 @@
     {
       if (check_region (hw_config->io_base, 0x0f))
 	{
-	  printk ("AEDSP16/SBPRO I/O port region is alredy in use.\n");
+	  printk ("AEDSP16/SBPRO I/O port region is already in use.\n");
 	  return -1;
 	}
     }
@@ -706,7 +706,7 @@
      * can allow me to release the requested region.
    */
   if (!(ae_init & INIT_MPU401))
-    request_region (hw_config->io_base, 0x0f, "aedsp16 (sbpro)");
+    request_region (hw_config->io_base, 0x0f, "AEDSP16 (SBPro)");
 #endif
 
   ae_init |= INIT_SBPRO;
@@ -721,7 +721,7 @@
 InitAEDSP16_MSS (struct address_info *hw_config)
 {
   /*
-     * If the card is alredy init'ed SBPRO, we can not init it to MSS too
+     * If the card is already init'ed SBPRO, we can not init it to MSS too
      * because the board can not emulate simultaneously MSS and SBPRO.
    */
   if (ae_init & INIT_SBPRO)
@@ -736,7 +736,7 @@
    */
   if (check_region (hw_config->io_base, 0x08))
     {
-      printk ("MSS I/O port region is alredy in use.\n");
+      printk ("MSS I/O port region is already in use.\n");
       return -1;
     }
 
@@ -748,7 +748,7 @@
     {
       if (check_region (AEDSP16_BASE, 0x0f))
 	{
-	  printk ("AEDSP16 I/O port region is alredy in use.\n");
+	  printk ("AEDSP16 I/O port region is already in use.\n");
 	  return -1;
 	}
     }
@@ -774,11 +774,11 @@
      * can allow me to release the requested region. So when unloading
      * and then reloading it, we are going to have some nice Oops!
    */
-  request_region (hw_config->io_base, 0x08, "aedsp16 (mss)");
+  request_region (hw_config->io_base, 0x08, "AEDSP16 (MSS)");
 #endif
 
   if (!(ae_init & INIT_MPU401))
-    request_region (AEDSP16_BASE, 0x0f, "aedsp16 (sbpro)");
+    request_region (AEDSP16_BASE, 0x0f, "AEDSP16 (SBPro)");
 
   ae_init |= INIT_MSS;
   return 0;
@@ -801,7 +801,7 @@
    */
   if (check_region (hw_config->io_base, 0x02))
     {
-      printk ("SB I/O port region is alredy in use.\n");
+      printk ("SB I/O port region is already in use.\n");
       return -1;
     }
 
@@ -813,15 +813,15 @@
     {
       if (check_region (AEDSP16_BASE, 0x0f))
 	{
-	  printk ("AEDSP16 I/O port region is alredy in use.\n");
+	  printk ("AEDSP16 I/O port region is already in use.\n");
 	  return -1;
 	}
     }
 
   /*
      * If mpu401, the irq and dma are not important, do not touch it
-     * because we may use the default if sbpro is not yet configured,
-     * we may use the sbpro ones if configured, and nothing wrong
+     * because we may use the default if SBPro is not yet configured,
+     * we may use the SBPro ones if configured, and nothing wrong
      * should happen.
      *
      * The mirq default is 0, but once set it to non-0 value, we should
@@ -837,11 +837,11 @@
      * request any region because there is not a uninit routine that
      * can allow me to release the requested region.
    */
-  request_region (hw_config->io_base, 0x02, "aedsp16 (mpu401)");
+  request_region (hw_config->io_base, 0x02, "AEDSP16 (mpu401)");
 #endif
 
   if (!(ae_init & (INIT_MSS | INIT_SBPRO)))
-    request_region (AEDSP16_BASE, 0x0f, "aedsp16 (sbpro)");
+    request_region (AEDSP16_BASE, 0x0f, "AEDSP16 (SBPro)");
 
   ae_init |= INIT_MPU401;
   return 0;
@@ -859,7 +859,7 @@
 ResetAEDSP16 (void)
 {
 #if defined(AEDSP16_DEBUG)
-  printk ("[aedsp16] ResetAEDSP16 called.\n");
+  printk ("[AEDSP16] ResetAEDSP16 called.\n");
 #endif
   return InitAEDSP16 (RESET_DSP16);
 }
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/audio.c linux/drivers/sound/audio.c
--- v2.0.2/linux/drivers/sound/audio.c	Wed Jul  3 22:05:12 1996
+++ linux/drivers/sound/audio.c	Sat Jul  6 11:31:42 1996
@@ -25,7 +25,7 @@
 #define OFF		0
 
 static int      audio_mode[MAX_AUDIO_DEV];
-static int      dev_nblock[MAX_AUDIO_DEV];	/* 1 if in noblocking mode */
+static int      dev_nblock[MAX_AUDIO_DEV];	/* 1 if in nonblocking mode */
 
 #define		AM_NONE		0
 #define		AM_WRITE	1
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/configure.c linux/drivers/sound/configure.c
--- v2.0.2/linux/drivers/sound/configure.c	Wed Jul  3 22:05:12 1996
+++ linux/drivers/sound/configure.c	Sat Jul  6 12:12:10 1996
@@ -68,8 +68,8 @@
 		B (OPT_MSS) | B (OPT_GUS16) | B (OPT_GUSMAX) | B (OPT_TRIX) | \
 		B (OPT_SSCAPE)| B(OPT_MAD16) | B(OPT_CS4232))
 #define MPU_DEVS (B(OPT_PSS)|\
-		  B(OPT_CS4232)|B(OPT_SPNP)|B(OPT_MAUI))
-#define UART401_DEVS (SBDSP_DEVS|B(OPT_TRIX)|B(OPT_MAD16)|B(OPT_SSCAPE))
+		  B(OPT_CS4232)|B(OPT_SPNP)|B(OPT_MAUI)|B(OPT_SSCAPE))
+#define UART401_DEVS (SBDSP_DEVS|B(OPT_TRIX)|B(OPT_MAD16))
 #define MIDI_CARDS (MPU_DEVS | UART401_DEVS | \
 		    B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | \
 		    B (OPT_GUS) | B (OPT_TRIX) | B (OPT_SSCAPE)|B(OPT_MAD16) | \
@@ -148,7 +148,7 @@
 char           *questions[] =
 {
   "ProAudioSpectrum 16 support",
-  "SoundBlaster (SB, SBPro, SB16, clones) support",
+  "Sound Blaster (SB, SBPro, SB16, clones) support",
   "Generic OPL2/OPL3 FM synthesizer support",
   "Gravis Ultrasound support",
   "MPU-401 support (NOT for SB16)",
@@ -157,7 +157,7 @@
   "16 bit sampling option of GUS (_NOT_ GUS MAX)",
   "GUS MAX support",
   "Microsoft Sound System support",
-  "Ensoniq Soundscape support",
+  "Ensoniq SoundScape support",
   "MediaTrix AudioTrix Pro support",
   "Support for MAD16 and/or Mozart based cards",
   "Support for Crystal CS4232 based (PnP) cards",
@@ -183,10 +183,10 @@
   "you have some other card made by MediaVision or Logitech as\n"
   "they are not PAS16 compatible.\n",
 
-  "Enable this if you have an original SoundBlaster card made by\n"
+  "Enable this if you have an original Sound Blaster card made by\n"
   "Creative Labs or a 100%% hardware compatible clone. For an\n"
   "unknown card you may want to try this if it claims to be\n"
-  "SoundBlaster compatible.\n",
+  "Sound Blaster compatible.\n",
 
   "Enable this option if your sound card has a Yamaha OPL2 or OPL3\n"
   "FM synthesizer chip.\n",
@@ -219,7 +219,7 @@
   "card made by Microsoft or the Aztech SG 16 Pro or NX16 Pro.\n",
 
   "Enable this if you have a sound card based on the Ensoniq\n"
-  "Soundscape chipset. Such cards are being manufactured by Ensoniq,\n"
+  "SoundScape chipset. Such cards are being manufactured by Ensoniq,\n"
   "Spea and Reveal (Reveal makes other cards as well).\n",
 
   "Enable this option if you have the AudioTrix Pro sound card\n"
@@ -240,10 +240,10 @@
   "Use this option to enable experimental support for cards that\n"
   "use the Plug and Play protocol.\n",
 
-  "Enable this option if your card is a SoundBlaster Pro or\n"
-  "SoundBlaster 16. It also works with many SoundBlaster Pro clones.\n",
+  "Enable this option if your card is a Sound Blaster Pro or\n"
+  "Sound Blaster 16. It also works with many Sound Blaster Pro clones.\n",
 
-  "Enable this if you have a SoundBlaster 16, including the AWE32.\n",
+  "Enable this if you have a Sound Blaster 16, including the AWE32.\n",
 
   "Enable this if you have an Audio Excel DSP16 card. See the file\n"
   "Readme.aedsp16 for more information.\n",
@@ -748,19 +748,19 @@
 		  "Check from manual of the card");
 
   ask_int_choice (B (OPT_SB), "SBC_IRQ",
-		  "SoundBlaster IRQ",
+		  "Sound Blaster IRQ",
 		  FMT_INT,
 		  7,
 		  "Check from manual of the card");
 
   ask_int_choice (B (OPT_SB), "SBC_DMA",
-		  "SoundBlaster DMA",
+		  "Sound Blaster DMA",
 		  FMT_INT,
 		  1,
 		  "0, 1 or 3");
 
   ask_int_choice (B (OPT_SB), "SB_DMA2",
-		"SoundBlaster 16 bit DMA (_REQUIRED_for SB16, Jazz16, SMW)",
+		"Sound Blaster 16 bit DMA (_REQUIRED_for SB16, Jazz16, SMW)",
 		  FMT_INT,
 		  5,
 		  "5, 6 or 7 (use 1 for 8 bit cards)");
@@ -775,7 +775,7 @@
 		  "SB MPU401 IRQ (Jazz16, SM Wave and ES1688)",
 		  FMT_INT,
 		  -1,
-		  "Check from manual of the card");
+		  "Use -1 with SB16");
 
   ask_int_choice (B (OPT_PAS), "PAS_IRQ",
 		  "PAS16 IRQ",
@@ -944,31 +944,31 @@
 		  "0, 1 or 3");
 
   ask_int_choice (B (OPT_SSCAPE), "SSCAPE_BASE",
-		  "Soundscape MIDI I/O base",
+		  "SoundScape MIDI I/O base",
 		  FMT_HEX,
 		  0x330,
 		  "320, 330, 340 or 350");
 
   ask_int_choice (B (OPT_SSCAPE), "SSCAPE_IRQ",
-		  "Soundscape MIDI IRQ",
+		  "SoundScape MIDI IRQ",
 		  FMT_INT,
 		  9,
 		  "");
 
   ask_int_choice (B (OPT_SSCAPE), "SSCAPE_DMA",
-		  "Soundscape initialization DMA",
+		  "SoundScape initialization DMA",
 		  FMT_INT,
 		  3,
 		  "0, 1 or 3");
 
   ask_int_choice (B (OPT_SSCAPE), "SSCAPE_MSS_BASE",
-		  "Soundscape audio I/O base",
+		  "SoundScape audio I/O base",
 		  FMT_HEX,
 		  0x534,
 		  "534, 608, E84 or F44");
 
   ask_int_choice (B (OPT_SSCAPE), "SSCAPE_MSS_IRQ",
-		  "Soundscape audio IRQ",
+		  "SoundScape audio IRQ",
 		  FMT_INT,
 		  11,
 		  "7, 9, 10 or 11");
@@ -1365,10 +1365,10 @@
 	{
 
 	  if (think_positively (
-	    "Do you want support for the Audio Excel SoundBlaster Pro mode",
+	    "Do you want support for the Audio Excel Sound Blaster Pro mode",
 				 1,
 				 "Enable this option if you want the Audio Excel sound card to operate\n"
-				 "in SoundBlaster Pro mode.\n"))
+				 "in Sound Blaster Pro mode.\n"))
 	    {
 	      printf ("#define AEDSP16_SBPRO\n");
 	      sel1 = 1;
@@ -1403,7 +1403,7 @@
     {
     genld_again:
       if (think_positively ("Do you wish to include an LD file", 1,
-			    "If you want to emulate the SoundBlaster card and you have a DSPxxx.LD\n"
+			    "If you want to emulate the Sound Blaster card and you have a DSPxxx.LD\n"
 		      "file then you must include the LD in the kernel.\n"))
 	{
 	  char            path[512];
@@ -1430,7 +1430,7 @@
 	{
 	  FILE           *sf = fopen ("synth-ld.h", "w");
 
-	  fprintf (sf, "/* automaticaly generated by configure */\n");
+	  fprintf (sf, "/* automatically generated by configure */\n");
 	  fprintf (sf, "unsigned char pss_synth[1];\n"
 		   "#define pss_synthLen 0\n");
 	  fclose (sf);
@@ -1443,7 +1443,7 @@
 
       if (think_positively ("Do you want to include TRXPRO.HEX in your kernel",
 			    1,
-	"The MediaTrix AudioTrix Pro has an onboard microcontroller which\n"
+	"The MediaTrix AudioTrix Pro has an on-board microcontroller which\n"
 			    "needs to be initialized by downloading the code from the file TRXPRO.HEX\n"
 			    "in the DOS driver directory. If you don't have the TRXPRO.HEX file handy\n"
 			    "you may skip this step. However, the SB and MPU-401 modes of AudioTrix\n"
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/cs4232.c linux/drivers/sound/cs4232.c
--- v2.0.2/linux/drivers/sound/cs4232.c	Wed Jul  3 22:05:13 1996
+++ linux/drivers/sound/cs4232.c	Sat Jul  6 11:31:42 1996
@@ -5,7 +5,7 @@
  * a PnP compatible chip which contains a CS4231A codec, SB emulation,
  * a MPU401 compatible MIDI port, joystick and synthesizer and IDE CD-ROM 
  * interfaces. This is just a temporary driver until full PnP support
- * gets inplemented. Just the WSS codec, FM synth and the MIDI ports are
+ * gets implemented. Just the WSS codec, FM synth and the MIDI ports are
  * supported. Other interfaces are left uninitialized.
  */
 /*
@@ -142,14 +142,14 @@
  */
 
       CS_OUT2 (0x15, 0x00);	/* Select logical device 0 (WSS/SB/FM) */
-      CS_OUT3 (0x47, (base >> 8) & 0xff, base & 0xff);	/* WSSbase */
+      CS_OUT3 (0x47, (base >> 8) & 0xff, base & 0xff);	/* WSS base */
 
       if (check_region (0x388, 4))	/* Not free */
-	CS_OUT3 (0x48, 0x00, 0x00)	/* FMbase off */
+	CS_OUT3 (0x48, 0x00, 0x00)	/* FM base off */
 	  else
-	CS_OUT3 (0x48, 0x03, 0x88);	/* FMbase 0x388 */
+	CS_OUT3 (0x48, 0x03, 0x88);	/* FM base 0x388 */
 
-      CS_OUT3 (0x42, 0x00, 0x00);	/* SBbase off */
+      CS_OUT3 (0x42, 0x00, 0x00);	/* SB base off */
       CS_OUT2 (0x22, irq);	/* SB+WSS IRQ */
       CS_OUT2 (0x2a, dma1);	/* SB+WSS DMA */
 
@@ -186,7 +186,7 @@
       if (mpu_base != 0 && mpu_irq != 0)
 	{
 	  CS_OUT2 (0x15, 0x03);	/* Select logical device 3 (MPU) */
-	  CS_OUT3 (0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff);	/* MPUbase */
+	  CS_OUT3 (0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff);	/* MPU base */
 	  CS_OUT2 (0x22, mpu_irq);	/* MPU IRQ */
 	  CS_OUT2 (0x33, 0x01);	/* Activate logical dev 3 */
 	}
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h
--- v2.0.2/linux/drivers/sound/dev_table.h	Wed Jul  3 22:05:13 1996
+++ linux/drivers/sound/dev_table.h	Sat Jul  6 11:31:43 1996
@@ -34,7 +34,7 @@
 
 struct driver_info {
 	char *driver_id;
-	int card_subtype;	/* Driver spesific. Usually 0 */
+	int card_subtype;	/* Driver specific. Usually 0 */
 	int card_type;		/*	From soundcard.h	*/
 	char *name;
 	void (*attach) (struct address_info *hw_config);
@@ -329,7 +329,7 @@
 		{"MIDI6850", 0, SNDCARD_UART6850,"6860 UART Midi",	attach_uart6850, probe_uart6850, unload_uart6850},
 #endif
 #ifdef CONFIG_SB
-		{"SBLAST", 0, SNDCARD_SB,	"SoundBlaster",		attach_sb_card, probe_sb, unload_sb},
+		{"SBLAST", 0, SNDCARD_SB,	"Sound Blaster",		attach_sb_card, probe_sb, unload_sb},
 #ifdef CONFIG_MIDI
 		{"UART401", 0, SNDCARD_UART401,"MPU-401 UART",	attach_uart401, probe_uart401, unload_uart401},
 #endif
@@ -342,13 +342,13 @@
 		{"GUSPNP", 1, SNDCARD_GUSPNP,	"GUS PnP",	attach_gus_card, probe_gus, unload_gus},
 #endif
 #ifdef CONFIG_SSCAPE
-		{"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq Soundscape",	attach_sscape, probe_sscape, unload_sscape},
+		{"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq SoundScape",	attach_sscape, probe_sscape, unload_sscape},
 		{"SSCAPEMSS", 0, SNDCARD_SSCAPE_MSS,	"MS Sound System (SoundScape)",	attach_ss_ms_sound, probe_ss_ms_sound, unload_ss_ms_sound},
 #endif
 #ifdef CONFIG_TRIX
-		{"TRXPRO", 0, SNDCARD_TRXPRO, "MediaTriX AudioTriX Pro",	attach_trix_wss, probe_trix_wss, unload_trix_wss},
-		{"TRXPROSB", 0, SNDCARD_TRXPRO_SB, "AudioTriX (SB mode)",	attach_trix_sb, probe_trix_sb, unload_trix_sb},
-		{"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTriX MIDI",	attach_trix_mpu, probe_trix_mpu, unload_trix_mpu},
+		{"TRXPRO", 0, SNDCARD_TRXPRO, "MediaTrix AudioTrix Pro",	attach_trix_wss, probe_trix_wss, unload_trix_wss},
+		{"TRXPROSB", 0, SNDCARD_TRXPRO_SB, "AudioTrix (SB mode)",	attach_trix_sb, probe_trix_sb, unload_trix_sb},
+		{"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTrix MIDI",	attach_trix_mpu, probe_trix_mpu, unload_trix_mpu},
 #endif
 		{NULL, 0, 0,		"*?*",			NULL, NULL, NULL}
 	};
@@ -531,7 +531,7 @@
 
 int sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan);
 void sound_free_dmap (int dev, struct dma_buffparms *dmap);
-extern int soud_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info);
+extern int sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info);
 void install_pnp_sounddrv(struct pnp_sounddev *drv);
 int sndtable_probe (int unit, struct address_info *hw_config);
 int sndtable_init_card (int unit, struct address_info *hw_config);
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c
--- v2.0.2/linux/drivers/sound/dmabuf.c	Wed Jul  3 22:05:13 1996
+++ linux/drivers/sound/dmabuf.c	Sat Jul  6 11:31:42 1996
@@ -83,7 +83,7 @@
       sz /= 8;			/* #bits -> #bytes */
 
       /*
-         * Compute a buffer size for time not exeeding 1 second.
+         * Compute a buffer size for time not exceeding 1 second.
          * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds
          * of sound (using the current speed, sample size and #channels).
        */
@@ -120,8 +120,8 @@
   else
     {
       /*
-         * The process has specified the buffer sice with SNDCTL_DSP_SETFRAGMENT or
-         * the buffer sice computation has already been done.
+         * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or
+         * the buffer size computation has already been done.
        */
       if (dmap->fragment_size > (audio_devs[dev]->buffsize / 2))
 	dmap->fragment_size = (audio_devs[dev]->buffsize / 2);
@@ -661,7 +661,7 @@
     }
 
   if (dmap->subdivision != 0 ||
-      dmap->fragment_size)	/* Loo late to change */
+      dmap->fragment_size)	/* Too late to change */
     return -(EINVAL);
 
   if (fact > MAX_REALTIME_FACTOR)
@@ -683,7 +683,7 @@
     return -(EIO);
 
   if (dmap->subdivision != 0 ||
-      dmap->fragment_size)	/* Loo late to change */
+      dmap->fragment_size)	/* Too late to change */
     return -(EINVAL);
 
   bytes = fact & 0xffff;
@@ -1273,7 +1273,7 @@
     restart = 1;
 
 /*
- * Bypass buffering if using mmaped access
+ * Bypass buffering if using mmapped access
  */
 
   if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c
--- v2.0.2/linux/drivers/sound/dmasound.c	Tue May 21 19:52:37 1996
+++ linux/drivers/sound/dmasound.c	Sat Jul  6 11:31:43 1996
@@ -57,7 +57,7 @@
 			to cut data only at sample sizes, buffer size is now
 			a kernel runtime option, implemented fsync() & several
 			minor improvements
-		++Guenther: useful hints and bugfixes, cross-checked it for
+		++Guenther: useful hints and bug fixes, cross-checked it for
 			Falcons
 
 1996/3/9	++geert: support added for Amiga, A-law, 16-bit little endian.
@@ -99,7 +99,7 @@
 
 #ifdef CONFIG_AMIGA
    /*
-    *	The minimum period for audio depends on htotal (for OCS/ECS/AGA)
+    *	The minimum period for audio depends on total (for OCS/ECS/AGA)
     *	(Imported from arch/m68k/amiga/amisound.c)
     */
 
@@ -307,7 +307,7 @@
 
 #ifdef HAS_14BIT_TABLES
 
-/* 14 bit mu-law (lsb) */
+/* 14 bit mu-law (LSB) */
 
 static char alaw2dma14l[] = {
         33,     33,     33,     33,     33,     33,     33,     33,
@@ -344,7 +344,7 @@
         14,     12,     10,      8,      6,      4,      2,      0
 };
 
-/* 14 bit A-law (lsb) */
+/* 14 bit A-law (LSB) */
 
 static char alaw2dma14l[] = {
         32,     32,     32,     32,     32,     32,     32,     32,
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/gus_vol.c linux/drivers/sound/gus_vol.c
--- v2.0.2/linux/drivers/sound/gus_vol.c	Wed Jul  3 22:05:13 1996
+++ linux/drivers/sound/gus_vol.c	Sat Jul  6 11:31:42 1996
@@ -81,7 +81,7 @@
     return ((15 << 8) | 255);
 
   /*
-   * Convert to gus's logarithmic form with 4 bit exponent i and 8 bit
+   * Convert to GUS's logarithmic form with 4 bit exponent i and 8 bit
    * mantissa m.
    */
   n = x;
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c
--- v2.0.2/linux/drivers/sound/gus_wave.c	Wed Jul  3 22:05:13 1996
+++ linux/drivers/sound/gus_wave.c	Sat Jul  6 11:31:42 1996
@@ -1666,7 +1666,7 @@
 
   if ((err = DMAbuf_open_dma (gus_devnum)) < 0)
     {
-      /* printk ("GUS: Loading saples without DMA\n"); */
+      /* printk ("GUS: Loading samples without DMA\n"); */
       gus_no_dma = 1;		/* Upload samples using PIO */
     }
   else
@@ -1788,7 +1788,7 @@
       if ((free_mem_ptr / GUS_BANK_SIZE) !=
 	  ((free_mem_ptr + patch.len) / GUS_BANK_SIZE))
 	{
-	  unsigned long   tmp_mem =	/* Aling to 256K */
+	  unsigned long   tmp_mem =	/* Align to 256K */
 	  ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;
 
 	  if ((tmp_mem + patch.len) > gus_mem_size)
@@ -2514,7 +2514,7 @@
   if (audio_devs[dev]->dmachan1 > 3)
     dma_command |= 0x04;	/* 16 bit DMA channel */
 
-  gus_write8 (0x41, dma_command);	/* Kickstart */
+  gus_write8 (0x41, dma_command);	/* Kick start */
 
   if (chn == (gus_audio_channels - 1))	/* Last channel */
     {
@@ -2715,7 +2715,7 @@
   guswave_set_instr (dev, voice, info->pgm_num);
 
   voices[voice].expression_vol =
-    info->controllers[CTL_EXPRESSION];	/* Just msb */
+    info->controllers[CTL_EXPRESSION];	/* Just MSB */
   voices[voice].main_vol =
     (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128;
   voices[voice].panning =
@@ -2862,7 +2862,7 @@
 				 */
 
 	offs += sample_ptrs[sample];	/*
-					 * Begin offsess + offset to DRAM
+					 * Begin offsets + offset to DRAM
 					 */
 
 	for (n = 0; n < l; n++)
@@ -2907,7 +2907,7 @@
 				 */
 
 	offs += sample_ptrs[sample];	/*
-					 * Begin offsess + offset to DRAM
+					 * Begin offsets + offset to DRAM
 					 */
 
 	for (n = 0; n < l; n++)
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/lowlevel/aci.c linux/drivers/sound/lowlevel/aci.c
--- v2.0.2/linux/drivers/sound/lowlevel/aci.c	Wed Jul  3 22:05:14 1996
+++ linux/drivers/sound/lowlevel/aci.c	Sat Jul  6 11:31:42 1996
@@ -63,7 +63,7 @@
 
 #undef  DEBUG             /* if defined, produce a verbose report via syslog */
 
-int aci_port = 0x354; /* as determined by bit 4 in the Opti 929 MC4 register */
+int aci_port = 0x354; /* as determined by bit 4 in the OPTi 929 MC4 register */
 unsigned char aci_idcode[2] = {0, 0};         /* manufacturer and product ID */
 unsigned char aci_version = 0;                       /* ACI firmware version */
 int aci_solo;                     /* status bit of the card that can't be    *
@@ -129,7 +129,7 @@
 /*
  * The four ACI command types (implied, write, read and indexed) can
  * be sent to the microcontroller using the following four functions.
- * If a problem occured, they return -1.
+ * If a problem occurred, they return -1.
  */
 
 static int implied_cmd(unsigned char opcode)
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c
--- v2.0.2/linux/drivers/sound/mad16.c	Wed Jul  3 22:05:14 1996
+++ linux/drivers/sound/mad16.c	Sat Jul  6 11:31:42 1996
@@ -17,7 +17,7 @@
  *      OPTi 82C929     MAD16 Pro
  *      OPTi 82C930
  *
- * These audio interface chips don't prduce sound themselves. They just
+ * These audio interface chips don't produce sound themselves. They just
  * connect some other components (OPL-[234] and a WSS compatible codec)
  * to the PC bus and perform I/O, DMA and IRQ address decoding. There is
  * also a UART for the MPU-401 mode (not 82C928/Mozart).
@@ -33,7 +33,7 @@
  *      0x00    - none
  *      0x02    - Sony 31A
  *      0x04    - Mitsumi
- *      0x06    - Panasonic (type "LaserMate", not "SoundBlaster")
+ *      0x06    - Panasonic (type "LaserMate", not "Sound Blaster")
  *      0x08    - Secondary IDE (address 0x170)
  *      0x0a    - Primary IDE (address 0x1F0)
  *      
@@ -83,8 +83,8 @@
  */
 
 #define MC0_PORT	0xf8c	/* Dummy port */
-#define MC1_PORT	0xf8d	/* SB address, CDROM interface type, joystick */
-#define MC2_PORT	0xf8e	/* CDROM address, IRQ, DMA, plus OPL4 bit */
+#define MC1_PORT	0xf8d	/* SB address, CD-ROM interface type, joystick */
+#define MC2_PORT	0xf8e	/* CD-ROM address, IRQ, DMA, plus OPL4 bit */
 #define MC3_PORT	0xf8f
 #define PASSWD_REG	0xf8f
 #define MC4_PORT	0xf90
@@ -200,14 +200,14 @@
   mad_write (MC7_PORT, 0);
   if ((tmp = mad_read (MC7_PORT)) != 0)
     {
-      DDB (printk ("MC7 not writeable (%x)\n", tmp));
+      DDB (printk ("MC7 not writable (%x)\n", tmp));
       return 0;
     }
 
   mad_write (MC7_PORT, 0xcb);
   if ((tmp = mad_read (MC7_PORT)) != 0xcb)
     {
-      DDB (printk ("MC7 not writeable2 (%x)\n", tmp));
+      DDB (printk ("MC7 not writable2 (%x)\n", tmp));
       return 0;
     }
 
@@ -248,7 +248,7 @@
       return 0;
     }
 
-  mad_write (MC1_PORT, tmp ^ 0x80);	/* Togge a bit */
+  mad_write (MC1_PORT, tmp ^ 0x80);	/* Toggle a bit */
   if ((tmp2 = mad_read (MC1_PORT)) != (tmp ^ 0x80))	/* Compare the bit */
     {
       mad_write (MC1_PORT, tmp);	/* Restore */
@@ -365,7 +365,7 @@
     return 0;
 
 /*
- * A temporarary kludge which drops the device back to mode1.
+ * A temporary kludge which drops the device back to mode1.
  * This removes problems with interrupts but disables full duplex.
  * A better solution should be introduced later.
  */
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/maui.c linux/drivers/sound/maui.c
--- v2.0.2/linux/drivers/sound/maui.c	Wed Jul  3 22:05:14 1996
+++ linux/drivers/sound/maui.c	Sat Jul  6 11:31:42 1996
@@ -181,7 +181,7 @@
 
 		if (c != 0x80)
 		  {
-		    printk ("Doanload not acknowledged\n");
+		    printk ("Download not acknowledged\n");
 		    return 0;
 		  }
 		else if (!(lines++ % 10))
@@ -452,7 +452,7 @@
       struct synth_operations *synth;
 
       /*
-       * Intercept patch loading calls so that they canbe handled
+       * Intercept patch loading calls so that they can be handled
        * by the Maui driver.
        */
 
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/midi_synth.c linux/drivers/sound/midi_synth.c
--- v2.0.2/linux/drivers/sound/midi_synth.c	Wed Jul  3 22:05:14 1996
+++ linux/drivers/sound/midi_synth.c	Sat Jul  6 11:31:42 1996
@@ -728,7 +728,7 @@
       if (!midi_devs[orig_dev]->putc (orig_dev, bytes[i]))
 	{
 /*
- * Hardware leve buffer is full. Abort the sysex message.
+ * Hardware level buffer is full. Abort the sysex message.
  */
 
 	  int             timeout = 0;
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/mpu401.c linux/drivers/sound/mpu401.c
--- v2.0.2/linux/drivers/sound/mpu401.c	Wed Jul  3 22:05:14 1996
+++ linux/drivers/sound/mpu401.c	Sat Jul  6 11:31:42 1996
@@ -506,7 +506,7 @@
      *  Verify that the device is really running.
      *  Some devices (such as Ensoniq SoundScape don't
      *  work before the on board processor (OBP) is initialized
-     *  by downloadin it's microcode.
+     *  by downloading its microcode.
    */
 
   if (!devc->initialized)
@@ -651,7 +651,7 @@
 	      ok = 1;
 	  }
 	else
-	  {			/* Device is not currently open. Use simplier method */
+	  {			/* Device is not currently open. Use simpler method */
 	    if (read_data (devc) == MPU_ACK)
 	      ok = 1;
 	  }
@@ -878,7 +878,7 @@
      *  Verify that the device is really running.
      *  Some devices (such as Ensoniq SoundScape don't
      *  work before the on board processor (OBP) is initialized
-     *  by downloadin it's microcode.
+     *  by downloading its microcode.
    */
 
   if (!devc->initialized)
@@ -1334,7 +1334,7 @@
   /*
      * The MPU-401 supports just a limited set of possible timebase values.
      * Since the applications require more choices, the driver has to
-     * program the HW to do it's best and to convert between the HW and
+     * program the HW to do its best and to convert between the HW and
      * actual timebases.
    */
 
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c
--- v2.0.2/linux/drivers/sound/opl3.c	Wed Jul  3 22:05:14 1996
+++ linux/drivers/sound/opl3.c	Sat Jul  6 11:31:42 1996
@@ -158,7 +158,7 @@
 opl3_detect (int ioaddr, int *osp)
 {
   /*
-   * This function returns 1 if the FM chicp is present at the given I/O port
+   * This function returns 1 if the FM chip is present at the given I/O port
    * The detection algorithm plays with the timer built in the FM chip and
    * looks for a change in the status register.
    *
@@ -238,7 +238,7 @@
     }
 
   /*
-   * There is a FM chicp in this address. Detect the type (OPL2 to OPL4)
+   * There is a FM chip in this address. Detect the type (OPL2 to OPL4)
    */
 
   if (signature == 0x06 && !force_opl3_mode)	/* OPL2 */
@@ -252,7 +252,7 @@
       detected_model = 3;
 
       /*
-       * Detect availability of OPL4 (_experimental_). Works propably
+       * Detect availability of OPL4 (_experimental_). Works probably
        * only after a cold boot. In addition the OPL4 port
        * of the chip may not be connected to the PC bus at all.
        */
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/opl3.h linux/drivers/sound/opl3.h
--- v2.0.2/linux/drivers/sound/opl3.h	Wed Jul  3 22:05:14 1996
+++ linux/drivers/sound/opl3.h	Sat Jul  6 11:31:43 1996
@@ -18,7 +18,7 @@
  *
  *	The percussive mode is implemented in the left side only.
  *
- *	With the above exeptions the both sides can be operated independently.
+ *	With the above exceptions the both sides can be operated independently.
  *	
  *	A 4 OP voice can be created by setting the corresponding
  *	bit at offset 4 of the right side.
@@ -144,7 +144,7 @@
  *	register offset).
  *
  *	For 4 OP voices the connection bit is used in the
- *	both halfs (gives 4 ways to connect the operators).
+ *	both halves (gives 4 ways to connect the operators).
  */
 #define FEEDBACK_CONNECTION				0xc0
 #define   FEEDBACK_MASK				0x0e	/* Valid just for 1st OP of a voice */
@@ -153,7 +153,7 @@
  *	In the 4 OP mode there is four possible configurations how the
  *	operators can be connected together (in 2 OP modes there is just
  *	AM or FM). The 4 OP connection mode is defined by the rightmost
- *	bit of the FEEDBACK_CONNECTION (0xC0-0xC8) on the both halfs.
+ *	bit of the FEEDBACK_CONNECTION (0xC0-0xC8) on the both halves.
  *
  *	First half	Second half	Mode
  *
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c
--- v2.0.2/linux/drivers/sound/pas2_card.c	Wed Jul  3 22:05:14 1996
+++ linux/drivers/sound/pas2_card.c	Sat Jul  6 11:31:42 1996
@@ -25,7 +25,7 @@
  * be relative to the given base -register
  */
 
-int             translat_code;
+int             translate_code;
 static int      pas_intr_mask = 0;
 static int      pas_irq = 0;
 static int      pas_sb_base = 0;
@@ -46,13 +46,13 @@
 unsigned char
 pas_read (int ioaddr)
 {
-  return inb (ioaddr ^ translat_code);
+  return inb (ioaddr ^ translate_code);
 }
 
 void
 pas_write (unsigned char data, int ioaddr)
 {
-  outb (data, ioaddr ^ translat_code);
+  outb (data, ioaddr ^ translate_code);
 }
 
 /******************* Begin of the Interrupt Handler ********************/
@@ -284,7 +284,7 @@
 
   outb (0xBC, 0x9A01);		/* Activate first board */
   outb (hw_config->io_base >> 2, 0x9A01);	/* Set base address */
-  translat_code = 0x388 ^ hw_config->io_base;
+  translate_code = 0x388 ^ hw_config->io_base;
   pas_write (1, 0xBF88);	/* Select one wait states */
 
   board_id = pas_read (0x0B8B);
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/pas2_mixer.c linux/drivers/sound/pas2_mixer.c
--- v2.0.2/linux/drivers/sound/pas2_mixer.c	Wed Jul  3 22:05:14 1996
+++ linux/drivers/sound/pas2_mixer.c	Sat Jul  6 11:31:42 1996
@@ -16,7 +16,7 @@
 #define DEB(what)		/* (what) */
 #endif
 
-extern int      translat_code;
+extern int      translate_code;
 extern char     pas_model;
 extern int     *pas_osp;
 extern int      pas_audiodev;
@@ -61,7 +61,7 @@
 
   if (pas_model == 4)
     {
-      outw (data | (data << 8), (ioaddr ^ translat_code) - 1);
+      outw (data | (data << 8), (ioaddr ^ translate_code) - 1);
       outb (0x80, 0);
     }
   else
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/pas2_pcm.c linux/drivers/sound/pas2_pcm.c
--- v2.0.2/linux/drivers/sound/pas2_pcm.c	Wed Jul  3 22:05:15 1996
+++ linux/drivers/sound/pas2_pcm.c	Sat Jul  6 11:31:42 1996
@@ -62,7 +62,7 @@
   tmp = pas_read (0x0B8A);
 
   /*
-     * Set anti-aliasing filters according to sample rate. You reall *NEED*
+     * Set anti-aliasing filters according to sample rate. You really *NEED*
      * to enable this feature for all normal recording unless you want to
      * experiment with aliasing effects.
      * These filters apply to the selected "recording" source.
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/patmgr.c linux/drivers/sound/patmgr.c
--- v2.0.2/linux/drivers/sound/patmgr.c	Wed Jul  3 22:05:15 1996
+++ linux/drivers/sound/patmgr.c	Sat Jul  6 11:31:42 1996
@@ -1,7 +1,7 @@
 /*
  * sound/patmgr.c
  *
- * The patch maneger interface for the /dev/sequencer
+ * The patch manager interface for the /dev/sequencer
  */
 /*
  * Copyright (C) by Hannu Savolainen 1993-1996
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/pss.c linux/drivers/sound/pss.c
--- v2.0.2/linux/drivers/sound/pss.c	Wed Jul  3 22:05:15 1996
+++ linux/drivers/sound/pss.c	Sat Jul  6 11:31:42 1996
@@ -260,7 +260,7 @@
 	    break;
 	  else
 	    {
-	      printk ("\nPSS: DownLoad timeout problems, byte %d=%d\n",
+	      printk ("\nPSS: Download timeout problems, byte %d=%d\n",
 		      count, size);
 	      return 0;
 	    }
@@ -710,7 +710,7 @@
 	    return -(EIO);
 	  }
 
-	if (!pss_get_dspword (devc, &tmp))	/* Read msb */
+	if (!pss_get_dspword (devc, &tmp))	/* Read MSB */
 	  {
 	    restore_flags (flags);
 	    return -(EIO);
@@ -718,7 +718,7 @@
 
 	buf.parm1 = tmp << 8;
 
-	if (!pss_get_dspword (devc, &tmp))	/* Read lsb */
+	if (!pss_get_dspword (devc, &tmp))	/* Read LSB */
 	  {
 	    restore_flags (flags);
 	    return -(EIO);
@@ -800,7 +800,7 @@
 
   /*
      * For some reason the card returns 0xff in the WSS status register
-     * immediately after boot. Propably MIDI+SB emulation algorithm
+     * immediately after boot. Probably MIDI+SB emulation algorithm
      * downloaded to the ADSP2115 spends some time initializing the card.
      * Let's try to wait until it finishes this task.
    */
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/sb.h linux/drivers/sound/sb.h
--- v2.0.2/linux/drivers/sound/sb.h	Wed Jul  3 22:05:15 1996
+++ linux/drivers/sound/sb.h	Sat Jul  6 11:31:42 1996
@@ -37,7 +37,7 @@
 #define MDL_SBPRO	4	/* SB Pro */
 #define MDL_SB16	5	/* SB16/32/AWE */
 #define MDL_JAZZ	10	/* Media Vision Jazz16 */
-#define MDL_SMW		11	/* Logitech Soundman Wave (Jazz16) */
+#define MDL_SMW		11	/* Logitech SoundMan Wave (Jazz16) */
 #define MDL_ESS		12	/* ESS ES688 and ES1688 */
 #define MDL_AZTECH	13	/* Aztech Sound Galaxy family */
 
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/sb_audio.c linux/drivers/sound/sb_audio.c
--- v2.0.2/linux/drivers/sound/sb_audio.c	Wed Jul  3 22:05:15 1996
+++ linux/drivers/sound/sb_audio.c	Sat Jul  6 11:31:42 1996
@@ -1,7 +1,7 @@
 /*
  * sound/sb_audio.c
  *
- * Audio routines for SoundBlaster compatible cards.
+ * Audio routines for Sound Blaster compatible cards.
  */
 /*
  * Copyright (C) by Hannu Savolainen 1993-1996
@@ -399,7 +399,7 @@
 }
 
 /*
- * SB2.01 spesific speed setup
+ * SB2.01 specific speed setup
  */
 
 static int
@@ -433,7 +433,7 @@
 }
 
 /*
- * SB Pro spesific routines
+ * SB Pro specific routines
  */
 
 static int
@@ -575,7 +575,7 @@
 }
 
 /*
- * ESS spesific routines
+ * ESS specific routines
  */
 
 static void
@@ -607,7 +607,7 @@
  * Set filter divider register
  */
 
-  speed = (speed * 9) / 20;	/* Set filter rolloff to 90% of speed/2 */
+  speed = (speed * 9) / 20;	/* Set filter roll-off to 90% of speed/2 */
   divider = 256 - 7160000 / (speed * 82);
   ess_write (devc, 0xa2, divider);
 
@@ -798,7 +798,7 @@
 }
 
 /*
- * SB16 spesific routines
+ * SB16 specific routines
  */
 
 static int
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- v2.0.2/linux/drivers/sound/sb_card.c	Wed Jul  3 22:05:15 1996
+++ linux/drivers/sound/sb_card.c	Sat Jul  6 11:31:42 1996
@@ -1,7 +1,7 @@
 /*
  * sound/sb_card.c
  *
- * Detection routine for the SoundBlaster cards.
+ * Detection routine for the Sound Blaster cards.
  */
 /*
  * Copyright (C) by Hannu Savolainen 1993-1996
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c
--- v2.0.2/linux/drivers/sound/sb_common.c	Wed Jul  3 22:05:15 1996
+++ linux/drivers/sound/sb_common.c	Sat Jul  6 11:31:42 1996
@@ -1,7 +1,7 @@
 /*
  * sound/sb_common.c
  *
- * Common routines for SoundBlaster compatible cards.
+ * Common routines for Sound Blaster compatible cards.
  */
 /*
  * Copyright (C) by Hannu Savolainen 1993-1996
@@ -25,7 +25,7 @@
 #include "sb.h"
 
 static sb_devc *detected_devc = NULL;	/* For communication from probe to init */
-static sb_devc *last_devc = NULL;	/* For MPU401 initalization */
+static sb_devc *last_devc = NULL;	/* For MPU401 initialization */
 static sb_devc *irq2devc[16] =
 {NULL};
 static unsigned char jazz_irq_bits[] =
@@ -34,14 +34,14 @@
 {0, 1, 0, 2, 0, 3, 0, 4};
 
 /*
- * Jazz16 chipset spesific control variables
+ * Jazz16 chipset specific control variables
  */
 
 static int      jazz16_base = 0;	/* Not detected */
 static unsigned char jazz16_bits = 0;	/* I/O relocation bits */
 
 /*
- * Logitech Soundman Wave spesific initialization code
+ * Logitech SoundMan Wave specific initialization code
  */
 
 #ifdef SMW_MIDI0001_INCLUDED
@@ -59,7 +59,7 @@
   unsigned long   limit;
 
   limit = jiffies + HZ / 10;	/*
-				   * The timeout is 0.1 secods
+				   * The timeout is 0.1 seconds
 				 */
 
   /*
@@ -79,7 +79,7 @@
 	}
     }
 
-  printk ("SoundBlaster: DSP Command(%x) Timeout.\n", val);
+  printk ("Sound Blaster: DSP Command(%x) Timeout.\n", val);
   return 0;
 }
 
@@ -173,7 +173,7 @@
 	break;
 
       default:
-	printk ("SoundBlaster: Unexpected interrupt\n");
+	printk ("Sound Blaster: Unexpected interrupt\n");
       }
 /*
  * Acknowledge interrupts 
@@ -345,7 +345,7 @@
     return 0;
 
 /*
- * OK so far. Now configure the IRQ and DMA channel used by the acrd.
+ * OK so far. Now configure the IRQ and DMA channel used by the card.
  */
   if (hw_config->irq < 1 || hw_config->irq > 15 ||
       jazz_irq_bits[hw_config->irq] == 0)
@@ -501,7 +501,7 @@
  *    Set DMA configuration register
  */
 
-  cfg = 0x50;			/* Extended mode DMA ebable */
+  cfg = 0x50;			/* Extended mode DMA enable */
 
   if (devc->dma8 > 3 || devc->dma8 < 0 || devc->dma8 == 2)
     {
@@ -649,7 +649,7 @@
   devc->caps = hw_config->driver_use_1;
 
   if (snd_set_irq_handler (hw_config->irq,
-			   sbintr, "soundblaster", devc->osp) < 0)
+			   sbintr, "sound blaster", devc->osp) < 0)
     {
       printk ("SB: Can't allocate IRQ%d\n", hw_config->irq);
       return;
@@ -696,7 +696,7 @@
       DDB (printk ("IRQ test OK (IRQ%d)\n", devc->irq));
     }
 
-  request_region (hw_config->io_base, 16, "soundblaster");
+  request_region (hw_config->io_base, 16, "sound blaster");
 
   switch (devc->major)
     {
@@ -758,12 +758,12 @@
 
   if (!(devc->caps & SB_NO_AUDIO))
     {
-      if (sound_alloc_dma (devc->dma8, "SoundBlaster8"))
+      if (sound_alloc_dma (devc->dma8, "Sound Blaster8"))
 	{
 	  printk ("SB: Can't allocate 8 bit DMA channel %d\n", devc->dma8);
 	}
       if (devc->dma16 >= 0 && devc->dma16 != devc->dma8)
-	if (sound_alloc_dma (devc->dma16, "SoundBlaster16"))
+	if (sound_alloc_dma (devc->dma16, "Sound Blaster16"))
 	  {
 	    printk ("SB: Can't allocate 16 bit DMA channel %d\n", devc->dma16);
 	  }
@@ -958,7 +958,7 @@
      * Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt
      * is disabled by default.
      *
-     * Btw the Zilog 5380 SCSI controller is located at MPU base + 0x10.
+     * BTW the Zilog 5380 SCSI controller is located at MPU base + 0x10.
    */
   {
     static unsigned char scsi_irq_bits[] =
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/sb_midi.c linux/drivers/sound/sb_midi.c
--- v2.0.2/linux/drivers/sound/sb_midi.c	Wed Jul  3 22:05:15 1996
+++ linux/drivers/sound/sb_midi.c	Sat Jul  6 11:31:43 1996
@@ -1,7 +1,7 @@
 /*
  * sound/sb_dsp.c
  *
- * The low level driver for the SoundBlaster DS chips.
+ * The low level driver for the Sound Blaster DS chips.
  */
 /*
  * Copyright (C) by Hannu Savolainen 1993-1996
@@ -147,13 +147,13 @@
   restore_flags (flags);
 }
 
-#define MIDI_SYNTH_NAME	"SoundBlaster Midi"
+#define MIDI_SYNTH_NAME	"Sound Blaster Midi"
 #define MIDI_SYNTH_CAPS	0
 #include "midi_synth.h"
 
 static struct midi_operations sb_midi_operations =
 {
-  {"SoundBlaster", 0, 0, SNDCARD_SB},
+  {"Sound Blaster", 0, 0, SNDCARD_SB},
   &std_midi_synth,
   {0},
   sb_midi_open,
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c
--- v2.0.2/linux/drivers/sound/sb_mixer.c	Wed Jul  3 22:05:15 1996
+++ linux/drivers/sound/sb_mixer.c	Sat Jul  6 11:31:43 1996
@@ -2,7 +2,7 @@
 /*
  * sound/sb_mixer.c
  *
- * The low level mixer driver for the SoundBlaster compatible cards.
+ * The low level mixer driver for the Sound Blaster compatible cards.
  */
 /*
  * Copyright (C) by Hannu Savolainen 1993-1996
@@ -352,7 +352,7 @@
 static struct mixer_operations sb_mixer_operations =
 {
   "SB",
-  "SoundBlaster",
+  "Sound Blaster",
   sb_mixer_ioctl
 };
 
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c
--- v2.0.2/linux/drivers/sound/sequencer.c	Wed Jul  3 22:05:16 1996
+++ linux/drivers/sound/sequencer.c	Sat Jul  6 11:31:43 1996
@@ -35,7 +35,7 @@
 /*
  * The seq_mode gives the operating mode of the sequencer:
  *      1 = level1 (the default)
- *      2 = level2 (extended capabilites)
+ *      2 = level2 (extended capabilities)
  */
 
 #define SEQ_1	1
@@ -69,7 +69,7 @@
 static volatile int iqhead = 0, iqtail = 0, iqlen = 0;
 static volatile int seq_playing = 0;
 static volatile int sequencer_busy = 0;
-static int      output_treshold;
+static int      output_threshold;
 static int      pre_event_timeout;
 static unsigned synth_open_mask;
 
@@ -688,7 +688,7 @@
 
       if ((ret = tmr->event (tmr_no, event_rec)) == TIMER_ARMED)
 	{
-	  if ((SEQ_MAX_QUEUE - qlen) >= output_treshold)
+	  if ((SEQ_MAX_QUEUE - qlen) >= output_threshold)
 	    {
 	      unsigned long   flags;
 
@@ -728,7 +728,7 @@
 
 	  request_sound_timer (time);
 
-	  if ((SEQ_MAX_QUEUE - qlen) >= output_treshold)
+	  if ((SEQ_MAX_QUEUE - qlen) >= output_threshold)
 	    {
 	      unsigned long   flags;
 
@@ -864,7 +864,7 @@
 
 	  request_sound_timer (time);
 
-	  if ((SEQ_MAX_QUEUE - qlen) >= output_treshold)
+	  if ((SEQ_MAX_QUEUE - qlen) >= output_threshold)
 	    {
 	      unsigned long   flags;
 
@@ -1003,7 +1003,7 @@
 
   seq_playing = 0;
 
-  if ((SEQ_MAX_QUEUE - qlen) >= output_treshold)
+  if ((SEQ_MAX_QUEUE - qlen) >= output_threshold)
     {
       unsigned long   flags;
 
@@ -1203,7 +1203,7 @@
 
   seq_sleep_flag.flags = WK_NONE;
   midi_sleep_flag.flags = WK_NONE;
-  output_treshold = SEQ_MAX_QUEUE / 2;
+  output_threshold = SEQ_MAX_QUEUE / 2;
 
   for (i = 0; i < num_synths; i++)
     if (pmgr_present[i])
@@ -1373,7 +1373,7 @@
 
   /*
    * This routine sends one byte to the Midi channel.
-   * If the output Fifo is full, it waits until there
+   * If the output FIFO is full, it waits until there
    * is space in the queue
    */
 
@@ -1843,7 +1843,7 @@
 	  tmp = 1;
 	if (tmp >= SEQ_MAX_QUEUE)
 	  tmp = SEQ_MAX_QUEUE - 1;
-	output_treshold = tmp;
+	output_threshold = tmp;
 	return 0;
       }
       break;
@@ -1908,7 +1908,7 @@
     case SEL_OUT:
       save_flags (flags);
       cli ();
-      if ((SEQ_MAX_QUEUE - qlen) < output_treshold)
+      if ((SEQ_MAX_QUEUE - qlen) < output_threshold)
 	{
 
 	  seq_sleep_flag.flags = WK_SLEEP;
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/sound_config.h linux/drivers/sound/sound_config.h
--- v2.0.2/linux/drivers/sound/sound_config.h	Wed Jul  3 22:05:16 1996
+++ linux/drivers/sound/sound_config.h	Sat Jul  6 11:31:43 1996
@@ -34,7 +34,7 @@
 
 /************* PCM DMA buffer sizes *******************/
 
-/* If you are using high playback or recording speeds, the default buffersize
+/* If you are using high playback or recording speeds, the default buffer size
    is too small. DSP_BUFFSIZE must be 64k or less.
 
    A rule of thumb is 64k for PAS16, 32k for PAS+, 16k for SB Pro and
@@ -97,7 +97,7 @@
 #define SND_DEV_DSP16	5	/* Like /dev/dsp but 16 bits/sample */
 #define SND_DEV_STATUS	6	/* /dev/sndstat */
 #define SND_DEV_AWFM	7	/* Reserved */
-#define SND_DEV_SEQ2	8	/* /dev/sequecer, level 2 interface */
+#define SND_DEV_SEQ2	8	/* /dev/sequencer, level 2 interface */
 #define SND_DEV_SNDPROC 9	/* /dev/sndproc for programmable devices */
 #define SND_DEV_PSS	SND_DEV_SNDPROC
 
@@ -127,8 +127,8 @@
 	char *name;
 	int driver_use_1;	/* Driver defined field 1 */
 	int driver_use_2;	/* Driver defined field 2 */
-	int *osp;	/* OS spesific info */
-	int card_subtype;	/* Driver spesific. Usually 0 */
+	int *osp;	/* OS specific info */
+	int card_subtype;	/* Driver specific. Usually 0 */
 };
 
 #define SYNTH_MAX_VOICES	32
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v2.0.2/linux/drivers/sound/soundcard.c	Wed Jul  3 22:05:16 1996
+++ linux/drivers/sound/soundcard.c	Sat Jul  6 11:31:42 1996
@@ -98,7 +98,7 @@
 
   if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS)
     {
-      printk ("SoundCard Error: The soundcard system has not been configured\n");
+      printk ("Sound Card Error: The soundcard system has not been configured\n");
       return -(ENXIO);
     }
 
@@ -734,7 +734,7 @@
 }
 
 int
-soud_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc * info)
+sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc * info)
 {
   printk ("Entered sound_map_buffer()\n");
   printk ("Exited sound_map_buffer()\n");
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c
--- v2.0.2/linux/drivers/sound/sscape.c	Wed Jul  3 22:05:17 1996
+++ linux/drivers/sound/sscape.c	Sat Jul  6 13:31:15 1996
@@ -1,7 +1,7 @@
 /*
  * sound/sscape.c
  *
- * Low level driver for Ensoniq Soundscape
+ * Low level driver for Ensoniq SoundScape
  */
 /*
  * Copyright (C) by Hannu Savolainen 1993-1996
@@ -304,10 +304,10 @@
       printk ("SSCAPE: Host interrupt, data=%02x\n", host_read (devc));
     }
 
-#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
+#if defined(CONFIG_MPU401) && defined(CONFIG_MIDI)
   if (bits & 0x01)
     {
-      uart401intr (irq, NULL, NULL);
+      mpuintr (irq, NULL, NULL);
       if (debug++ > 10)		/* Temporary debugging hack */
 	{
 	  sscape_write (devc, GA_INTENA_REG, 0x00);	/* Disable all interrupts */
@@ -436,8 +436,10 @@
       save_flags (flags);
       cli ();
       codec_dma_bits = sscape_read (devc, GA_CDCFG_REG);
+#if 0
       sscape_write (devc, GA_CDCFG_REG,
 		    codec_dma_bits & ~0x08);	/* Disable codec DMA */
+#endif
 
       if (devc->dma_allocated == 0)
 	{
@@ -716,10 +718,10 @@
   if (old_hardware)
     {
       valid_interrupts = valid_interrupts_old;
-      conf_printf ("Ensoniq Soundscape (old)", hw_config);
+      conf_printf ("Ensoniq SoundScape (old)", hw_config);
     }
   else
-    conf_printf ("Ensoniq Soundscape", hw_config);
+    conf_printf ("Ensoniq SoundScape", hw_config);
 
   for (i = 0; i < sizeof (valid_interrupts); i++)
     if (hw_config->irq == valid_interrupts[i])
@@ -785,17 +787,17 @@
   }
 #endif
 
-#if defined(CONFIG_MIDI) && defined(CONFIG_UART401)
-  if (probe_uart401 (hw_config))
+#if defined(CONFIG_MIDI) && defined(CONFIG_MPU401)
+  if (probe_mpu401 (hw_config))
     hw_config->always_detect = 1;
   {
     int             prev_devs;
 
     prev_devs = num_midis;
-    hw_config->name = "Soundscape";
+    hw_config->name = "SoundScape";
 
     hw_config->irq *= -1;	/* Negative value signals IRQ sharing */
-    attach_uart401 (hw_config);
+    attach_mpu401 (hw_config);
     hw_config->irq *= -1;	/* Restore it */
 
     if (num_midis == (prev_devs + 1))	/* The MPU driver installed itself */
@@ -824,7 +826,7 @@
 
   /*
      * First check that the address register of "ODIE" is
-     * there and that it has exactly 4 writeable bits.
+     * there and that it has exactly 4 writable bits.
      * First 4 bits
    */
   if ((save = inb (PORT (ODIE_ADDR))) & 0xf0)
@@ -938,7 +940,7 @@
   sscape_write (devc, GA_DMACFG_REG, 0x50);
 
   /*
-     * Take the gate-arry off of the DMA channel.
+     * Take the gate-array off of the DMA channel.
    */
   sscape_write (devc, GA_DMAB_REG, 0x20);
 
@@ -988,8 +990,8 @@
 void
 unload_sscape (struct address_info *hw_config)
 {
-#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
-  unload_uart401 (hw_config);
+#if defined(CONFIG_MPU401) && defined(CONFIG_MIDI)
+  unload_mpu401 (hw_config);
 #endif
   snd_release_irq (hw_config->irq);
 }
diff -u --recursive --new-file v2.0.2/linux/drivers/sound/trix.c linux/drivers/sound/trix.c
--- v2.0.2/linux/drivers/sound/trix.c	Wed Jul  3 22:05:18 1996
+++ linux/drivers/sound/trix.c	Sat Jul  6 11:31:43 1996
@@ -90,7 +90,7 @@
   if (kilroy_was_here)		/* Already initialized */
     return 0;
 
-  if (trix_read (0x15) != 0x71)	/* No asic signature */
+  if (trix_read (0x15) != 0x71)	/* No ASIC signature */
     {
       DDB (printk ("No AudioTrix ASIC signature found\n"));
       return 0;
diff -u --recursive --new-file v2.0.2/linux/include/asm-i386/posix_types.h linux/include/asm-i386/posix_types.h
--- v2.0.2/linux/include/asm-i386/posix_types.h	Wed Jul  3 22:05:19 1996
+++ linux/include/asm-i386/posix_types.h	Sat Jul  6 11:14:34 1996
@@ -57,7 +57,7 @@
 #define __FD_ZERO(fdsetp) \
 		__asm__ __volatile__("cld ; rep ; stosl" \
 			:"=m" (*(__kernel_fd_set *) (fdsetp)) \
-			:"a" (0), "c" (__FDSET_INTS), \
+			:"a" (0), "c" (__FDSET_LONGS), \
 			"D" ((__kernel_fd_set *) (fdsetp)) :"cx","di")
 
 #endif
diff -u --recursive --new-file v2.0.2/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.0.2/linux/include/linux/proc_fs.h	Mon May 20 08:21:04 1996
+++ linux/include/linux/proc_fs.h	Sat Jul  6 12:23:10 1996
@@ -125,6 +125,7 @@
 	PROC_SCSI_SEAGATE,
 	PROC_SCSI_T128,
 	PROC_SCSI_NCR53C7xx,
+	PROC_SCSI_NCR53C8XX,
 	PROC_SCSI_ULTRASTOR,
 	PROC_SCSI_7000FASST,
 	PROC_SCSI_EATA2X,
diff -u --recursive --new-file v2.0.2/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.0.2/linux/net/ipv4/tcp_input.c	Sat Jul  6 12:07:14 1996
+++ linux/net/ipv4/tcp_input.c	Sat Jul  6 13:32:44 1996
@@ -1863,7 +1863,7 @@
 			 * handle them locally, due to transparent proxying.
 			 * Thus, narrow down the test to what is really meant.
 			 */
-			if(th->rst || !th->syn || th->ack || (r = ip_chk_addr(daddr) == IS_BROADCAST || r == IS_MULTICAST))
+			if(th->rst || !th->syn || th->ack || (r = ip_chk_addr(daddr)) == IS_BROADCAST || r == IS_MULTICAST)
 #else
 			if(th->rst || !th->syn || th->ack || ip_chk_addr(daddr)!=IS_MYADDR)
 #endif
