diff -u --recursive --new-file v1.3.88/linux/CREDITS linux/CREDITS
--- v1.3.88/linux/CREDITS	Fri Apr 12 15:51:42 1996
+++ linux/CREDITS	Mon Apr 15 07:58:27 1996
@@ -187,6 +187,14 @@
 S: Fremont, CA 94536
 S: USA
 
+N: Chih-Jen Chang     
+E: chihjenc@scf.usc.edu
+E: chihjen@iis.sinica.edu.tw
+D: IGMP(Internet Group Management Protocol) version 2
+S: 3F, 65 Tajen street
+S: Tamsui town, Taipei county,
+S: Taiwan 251, Republic of China
+
 N: Raymond Chen
 E: raymondc@microsoft.com
 D: Author of Configure script
@@ -858,10 +866,12 @@
 S: United Kingdom
 
 N: Michael Neuffer
+E: mike@i-Connect.Net
 E: neuffer@goofy.zdv.uni-mainz.de
+W: http://www.i-Connect.Net/~mike/
 D: Developer and maintainer of the EATA-DMA SCSI driver
 D: Co-developer EATA-PIO SCSI driver
-D: Assorted other snippets 
+D: /proc/scsi and assorted other snippets 
 S: Zum Schiersteiner Grund 2
 S: 55127 Mainz
 S: Germany
@@ -968,6 +978,13 @@
 S: Gowrie ACT 2904
 S: Australia
 
+N: Gerard Roudier
+E: groudier@iplus.fr
+D: Contributed to asynchronous read-ahead improvement
+S: 21 Rue Carnot
+S: 95170 Deuil La Barre
+S: France
+
 N: Alessandro Rubini
 E: rubini@ipvvis.unipv.it
 D: the gpm mouse server and kernel support for it
@@ -1006,6 +1023,15 @@
 S: Sunnyvale, CA 94088-4132
 S: USA
 
+N: Simon Shapiro
+E: shimon@i-Connect.Net
+W: http://www.-i-Connect.Net/~shimon
+D: SCSI debugging
+D: Maintainer of the Debian Kernel packages
+S: 14355 SW Allen Blvd., Suite #140
+S: Beaverton, OR 97008
+S: USA
+
 N: Rick Sladkey
 E: jrs@world.std.com
 D: utility hacker: Emacs, NFS server, mount, kmem-ps, UPS debugger, strace, GDB
@@ -1127,6 +1153,16 @@
 S: Cambridge, Massachusetts 02139
 S: USA
 
+N: Tsu-Sheng Tsao
+E: tsusheng@scf.usc.edu
+D: IGMP(Internet Group Management Protocol) version 2
+S: 2F 14 ALY 31 LN 166 SEC 1 SHIH-PEI RD
+S: Taipei 
+S: Taiwan 112, Republic of China
+S: 24335 Delta Drive
+S: Diamond Bar, CA 91765
+S: USA
+
 N: Simmule Turner
 E: sturner@tele-tv.com
 D: Added swapping to filesystem
@@ -1305,22 +1341,4 @@
 D: Miscellaneous kernel fixes
 S: 3078 Sulphur Spring Court
 S: San Jose, California 95148
-S: USA
-
-N: Chih-Jen Chang     
-E: chihjenc@scf.usc.edu
-E: chihjen@iis.sinica.edu.tw
-D: IGMP(Internet Group Management Protocol) version 2
-S: 3F, 65 Tajen street
-S: Tamsui town, Taipei county,
-S: Taiwan 251, Republic of China
-
-N: Tsu-Sheng Tsao
-E: tsusheng@scf.usc.edu
-D: IGMP(Internet Group Management Protocol) version 2
-S: 2F 14 ALY 31 LN 166 SEC 1 SHIH-PEI RD
-S: Taipei 
-S: Taiwan 112, Republic of China
-S: 24335 Delta Drive
-S: Diamond Bar, CA 91765
 S: USA
diff -u --recursive --new-file v1.3.88/linux/Documentation/Changes linux/Documentation/Changes
--- v1.3.88/linux/Documentation/Changes	Sat Apr 13 18:22:06 1996
+++ linux/Documentation/Changes	Mon Apr 15 11:52:28 1996
@@ -3,23 +3,27 @@
 
 The installation information were removed because redundant.
 
-Last updated: 12 Apr 1996.
-Author: Alessandro Sigala `ssigala@globalnet.it'.
+Last updated: 14 Apr 1996.
+Author: Alessandro Sigala (ssigala@globalnet.it).
+
+Section "Upgrading to 1.3.x kernel" contributed by Chris Ricker
+(gt1355b@prism.gatech.edu).
 
 Current Releases
 ****************
 
-- Kernel modules 1.3.69
-- PPP daemon 2.2.0e
+- Kernel modules	 Broken: 1.3.57, Exp: 1.3.69f
+- PPP daemon		 Stable: 2.2.0e, Exp: 2.2.0f-BETA6
 - Dynamic linker (ld.so) 1.7.14
-- GNU CC 2.7.2
-- Binutils 2.6.0.12
-- Linux C Library 5.3.9
-- Linux C++ Library 2.7.1.4
-- Termcap 2.0.7
-- Procps 0.99a
-- Gpm 1.06
-- SysVinit 2.60
+- GNU CC		 2.7.2
+- Binutils		 2.6.0.12
+- Linux C Library	 Latest: 5.3.9, Stable: 5.2.18
+- Linux C++ Library	 2.7.1.4
+- Termcap		 2.0.7
+- Procps		 0.99a
+- Gpm			 1.06
+- SysVinit		 2.60
+- Util-linux		 2.5
 
 What you really need to upgrade
 *******************************
@@ -34,13 +38,13 @@
 ========
 
    The FIFO behavior is changed in latest 1.3.x kernel releases. You may
-upgrade to this version if the older version break.
+upgrade to 2.60 if the older version breaks.
 
 PPP daemon and utilities
 ========================
 
    To use the PPP protocol with the 1.3.x linux kernel, you need to
-upgrade the PPP package to version 2.2.0e.
+upgrade the PPP package to version 2.2.0e or the experimental 2.2.0f.
 
 Procps utilities
 ================
@@ -64,9 +68,9 @@
    The current Linux C Library release is 5.3.9. In this release there
 are some important changes that may break other programs, then read the
 `release.libc-5.3.9' file carefully!  You need to patch and recompile
-the `make' utility, or get it precompiled from the address written in
-the next section of this file.  If you don't want to patch and
-recompile the binaries you may try the release 5.2.18.
+the `make' utility, or get it precompiled from the address written at
+the end of this file.  If you don't want to patch and recompile the
+binaries you may try the release 5.2.18.
 
 The Termcap Library
 ===================
@@ -75,6 +79,212 @@
 read the `README' file contained into the package to get some important
 information about the `tgetent' function changes!
 
+Upgrading to 1.3.x kernel
+*************************
+
+   This section was prepared by Chris Ricker and based on material from
+the linux-kernel mailing list, Jared Mauch's web page "Software Victims
+of the 1.3 Kernel Development"
+(http://www2.nether.net/~jared/victim.html), and Axel Boldt's
+(boldt@math.ucsb.edu) Configure.help file, among other sources.
+
+   This section is intended primarily to help those that are new to the
+1.3.x series of Linux kernels.  In the ongoing effort to make a faster,
+better kernel and eventually achieve complete world domination, several
+features of the kernel have changed.  As a result, when you first
+upgrade to 1.3.x from 1.2.13, you will also have to upgrade several
+utilities that are closely associated with the kernel.
+
+Proc filesystem
+===============
+
+   Various changes in the /proc filesystem have been made, affecting ps,
+top, etc.  Running `top' or `ps -auwwx' will now give you a floating
+point exception. To fix the problem, upgrade to procps-0.99a.tar.gz,
+available at
+ftp://tsx-11.mit.edu/pub/linux/BETA/procps/procps-0.99a.tar.gz (or else
+don't run top or ps with fancy switches and live with the incorrect
+values ;-).
+
+Modules
+=======
+
+   1.3.x is almost completely modularized, 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
+(works fine for me) is modules-1.3.57.tar.gz, and the latest beta is
+modules-1.3.69f.tar.gz.  These should be available at the same place
+you picked up your kernel (ftp://ftp.cc.gatech.edu/pub/linux/kernel/)
+and the home page is 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 between 1 and 87, then it's time to upgrade
+module utilities from 1.3.57 to 1.3.69f (you'll only get this if you're
+running the latest binutils as well).  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 to run insmod to install a.out/ELF
+support so you can run insmod ;-).  If you have an all-ELF system, but
+need a.out for the occasional Netscape session, then you can do a.out
+support as a module.  Otherwise, you should probably leave it in the
+kernel.  Similarly, any partitions that you have to mount at startup
+have to have their necessary drivers compiled into the kernel, so don't
+get grandiose ideas about going completely modular and then forget to
+compile ext2fs support into your kernel ;-).
+
+PPP driver
+==========
+
+   The PPP driver was upgraded (and is still in somewhat of a a state of
+flux).  You need to be running a pppd from ppp-2.2.0.tar.gz or greater.
+The latest is 2.2.0e and is available at
+ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp-2.2.0e.tar.gz.
+
+Named pipes
+===========
+
+   Linux's handling of named pipes changed (it now does it The Right Way
+instead of the SunOS way ;-).  This broke some programs that depended
+on the SunOS behavior, most notably SysVinit.  If you're running 2.59
+or earlier, you will probably get a wierd error on shutdown in which
+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://ftp.cistron.nl/pub/people/miquels/debian/sysvinit-2.60.tar.gz.
+
+Uugetty
+=======
+
+   Older uugettys will not allow use of a bidirectional serial line.  To
+fix this problem, upgrade to
+ftp://sunsite.unc.edu/pub/Linux/system/Serial/getty_ps-2.0.7h.tar.gz.
+
+Console
+=======
+
+   The Linux console type has changed.  If your setup is old enough that
+you have problems, you'll need to update your termcap.  To fix, add
+linux to one of the types in /etc/termcap or snoop around
+http://www.ccil.org/~esr/ncurses.html (reputedly the latest universal
+termcap maintainer).  You may also need to update terminfo by running
+the following as root:
+
+   ln -s /usr/lib/terminfo/l/linux /usr/lib/terminfo/c/console
+
+Hdparm
+======
+
+   Hdparm has been upgraded to take advantage of the latest features of
+the kernel drivers.  The latest can be found at
+ftp://sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/hdparm-2.7.tar.gz.
+
+IP Accounting
+=============
+
+   IP accounting has now been integrated into the kernel.  To use this,
+you'll need to get ipfwadm from ftp://ftp.xos.nl/pub/linux/ipfwadm.  Get
+ipfwadm-2.0beta2.tar.gz if your kernel is 1.3.66 or later.
+
+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
+official release there is net-tools-1.2.0.tar.gz, and the latest
+release is net-tools-1.3.6-BETA5.tar.gz.  If you need the upgrade, you
+probably need the latest beta release.
+
+xntpd
+=====
+
+   Older versions of xntpd will not work with the latest kernels.
+Upgrade to xntp3.5c.tar.Z, available from
+http://www.eecis.udel.edu/~ntp/.
+
+Sound driver
+============
+
+   The sound driver was upgraded in the 1.3.x kernels, breaking vplay.
+To fix this problem, get a new version of the sndkit from
+ftp://ftp.best.com/pub/front/tasd/snd-util-3.5.tar.gz
+
+tcsh
+====
+
+   If tcsh acts funny, get the source from
+ftp://tesla.ee.cornell.edu/pub/tcsh and add #define SYSMALLOC in
+config_f.h before recompiling tcsh.  Binaries can be found in
+ftp://sunsite.unc.edu/pub/Linux/system/Shells/ and a corrected one will
+probably wind up there eventually.
+
+Make
+====
+
+   If make no longer works, you need to read the release notes for the
+libc you upgraded to.  The latest libc and release notes can be found at
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC.  This is NOT an error due
+to the kernel, though many people have mistakenly thought it is.  When
+you upgrade to libc-5.3.9, you have to patch make to get it to work.
+All of this is documented in the release notes with libc.
+
+Loop device
+===========
+
+   1.3.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 work on
+encrypted file system support can be found in
+ftp.funet.fi:/pub/OS/Linux/BETA/loop/des.1.tar.gz.
+
+Multiple device
+===============
+
+   Multiple device support (allowing you to group several partitions
+into one logical device) has also been added.  Check out
+ftp://sweet-smoke.ufr-info-p7.ibp.fr/pub/Linux/md034.tar.gz to try this
+out.
+
+Arp
+===
+
+   Arp daemon support has been added.  Check out
+http://www.loran.com/~layes/arpd/index.html for more info and a copy of
+arpd.
+
+Quota
+=====
+
+   Quota support has also been added.  You need to get
+ftp://sunsite.unc.edu/pub/Linux/system/Admin/quota_acct.tar.gz to enable
+quotas.  The version that is currently there does not compile, though I
+am uploading a patched one that will compile as I write this (look for
+quota-acct-modified.tgz).
+
+Please send info about any other packages that 1.3.x "broke" or about
+any new features of 1.3.x that require extra packages for use to Chris
+Ricker (gt1355b@prism.gatech.edu) or me.
+
+How to know the version of the installed programs
+*************************************************
+
+   There are some simple methods useful to know the version of the
+installed programs and libraries.
+
+GNU CC: gcc -v and gcc --version
+PPP: pppd -h (wrong but it show the version)
+Libc: ls -l /lib/libc.so.5
+LibC++: ls -l /usr/lib/libg++.so
+Binutils: ld -v
+dld: ldd -v and ldd -V
+termcap: ls -l /lib/libtermcap.so.*
+modules: insmod -V
+procps: ps --version
+
 Where to get the files
 **********************
 
@@ -128,15 +338,18 @@
 Modules utilities
 =================
 
-The latest public release
+The latest public release:
 ftp://sunsite.unc.edu/pub/Linux/kernel/modules-1.3.57.tar.gz
-The latest experimental release
+The latest experimental release:
 http://www.pi.se/blox/
 
 PPP Daemon and utilities
 ========================
 
+The latest public release:
 ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp-2.2.0e.tar.gz
+The latest experimental release:
+ftp://ftp.sii.com/pub/linux/ppp-2.2/ppp-2.2.0f.BETA6.tar.gz
 
 Procps utilities
 ================
@@ -156,3 +369,9 @@
 ftp://sunsite.unc.edu/pub/Linux/Incoming/sysvinit-2.60.tar.gz
 Next location:
 ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.60.tar.gz
+
+Util-linux
+==========
+
+ftp://sunsite.unc.edu/pub/Linux/system/Misc/util-linux-2.5.tar.gz
+
diff -u --recursive --new-file v1.3.88/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v1.3.88/linux/Documentation/Configure.help	Fri Apr 12 15:51:42 1996
+++ linux/Documentation/Configure.help	Mon Apr 15 10:03:25 1996
@@ -1225,27 +1225,29 @@
 CONFIG_SCSI_DTC3280
   This is support for DTC 3180/3280 SCSI Host Adaptors.  It does not
   use IRQ's.  It does not support parity on the SCSI bus.
-
-EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support
+ 
+EATA-DMA (DPT, NEC, ATT, Olivetti for ISA, EISA, PCI) support
 CONFIG_SCSI_EATA_DMA
-  This is support for a SCSI host adaptor. Please read the
-  SCSI-HOWTO, available via ftp (user: anonymous) at
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. If it doesn't work out of the
-  box, you may have to change some settings in
-  drivers/scsi/eata_dma.h. This driver is also available as a module (
-  = code which can be inserted in and removed from the running kernel
-  whenever you want). If you want to compile it as a module, say M
-  here and read Documentation/modules.txt.
+  This is support for the EATA-DMA protocol compliant SCSI Host Adaptors
+  like the SmartCache III/IV, SmartRAID controller families and the DPT 
+  PM2011B and PM2012B controllers.  
+  Please read the SCSI-HOWTO, available via ftp (user: anonymous) at
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. 
+  This driver is also available as a module (= code which can be inserted 
+  in and removed from the running kernel whenever you want). If you want 
+  to compile it as a module, say M here and read Documentation/modules.txt.
 
 EATA-PIO (old DPT PM2001, PM2012A) support
 CONFIG_SCSI_EATA_PIO
-  This driver supports all EATA-PIO SCSI host adaptors. You might want
-  to have a look at the settings in drivers/scsi/eata_pio.h and at the
-  SCSI-HOWTO, available via ftp (user: anonymous) at
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If you want to compile this
-  as a module ( = code which can be inserted in and removed from the
-  running kernel whenever you want), say M here and read
-  Documentation/modules.txt.
+  This driver supports all EATA-PIO protocol compliant SCSI Host Adaptors
+  like the DPT PM2001 and the PM2012A. EATA-DMA compliant HBAs can also use 
+  this driver but are discuraged from doing so, since this driver only 
+  supports harddisks and lacks numerous features.
+  You might want to have a look at the SCSI-HOWTO, available via ftp 
+  (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO.  
+  If you want to compile this as a module ( = code which can be inserted 
+  in and removed from the running kernel whenever you want), say M here 
+  and read Documentation/modules.txt.
 
 UltraStor 14F/34F support
 CONFIG_SCSI_U14_34F
@@ -3034,6 +3036,20 @@
   from some situations that the hardware watchdog will recover
   from. Equally it's a lot cheaper to install.
 
+Enhanced Real Time Clock Support
+CONFIG_RTC
+  If you enable this option and create a character special file
+  /dev/rtc with major number 10 and minor number 135 using mknod
+  ("man mknod"), you will get access to the real time clock built
+  into your computer. It can be used to generate signals from as
+  low as 1Hz up to 8192Hz, and can also be used as a 24 hour alarm.
+  It reports status information via the file /proc/rtc and its 
+  behaviour is set by various ioctls on /dev/rtc. People running
+  SMP versions of Linux should enable this option to read and set
+  the RTC clock in a SMP compatible fashion. If you think you
+  have a use for such a device (such as periodic data sampling), then 
+  say Y here, and go read the file Documentation/rtc.txt for details.
+
 Sound card support
 CONFIG_SOUND
   If you have a Sound Card in your Computer, i.e. if it can say more
@@ -3168,7 +3184,7 @@
 # LocalWords:  pppd Zilog ZS soundcards SRM bootloader ez mainmenu rarp ipfwadm
 # LocalWords:  RTNETLINK mknod xos MTU lwared Macs mac netatalk macs cs Wolff
 # LocalWords:  dartmouth flowerpt MultiMaster FlashPoint tudelft etherexpress
-# LocalWords:  ICL EtherTeam ETH IDESCSI TXC dmesg httpd hlt sjc barlow dlp mtu
+# LocalWords:  ICL EtherTeam ETH IDESCSI TXC SmartRAID SmartCache
 # LocalWords:  thesphere TwoServers BOOTP DHCP ncpfs BPQETHER BPQ chipsets MG
 # LocalWords:  bsd comp Sparcstation le SunOS ie Gracilis PackeTwin PT pt LU FX
 # LocalWords:  FX TEAC SoundBlaster CR CreativeLabs LCS mS ramdisk IDETAPE cmd
diff -u --recursive --new-file v1.3.88/linux/Documentation/rtc.txt linux/Documentation/rtc.txt
--- v1.3.88/linux/Documentation/rtc.txt	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/rtc.txt	Mon Apr 15 10:03:25 1996
@@ -0,0 +1,274 @@
+
+	Real Time Clock Driver for Linux
+	================================
+
+All PCs (even Alpha machines) have a Real Time Clock built into them.
+Usually they are built into the chipset of the computer, but some may
+actually have a Motorola MC146818 (or clone) on the board. This is the
+clock that keeps the date and time while your computer is turned off.
+
+However it can also be used to generate signals from a slow 2Hz to a
+relatively fast 8192Hz, in increments of powers of two. These signals
+are reported by interrupt number 8. (Oh! So *thats* what IRQ 8 is
+for...) It can also function as a 24hr alarm, raising IRQ 8 when the
+alarm goes off. The alarm can also be programmed to only check any
+subset of the three programmable values, meaning that it could be set to
+ring on the 30th second of the 30th minute of every hour, for example.
+The clock can also be set to generate an interrupt upon every clock
+update, thus generating a 1Hz signal.
+
+The interrupts are reported via /dev/rtc (major 10, minor 135, read only
+character device) in the form of an unsigned long. The low byte contains
+the type of interrupt (update-done, alarm-rang, or periodic) that was
+raised, and the remaining bytes contain the number of interrupts since
+the last read.  Status information is reported through the pseudo-file
+/proc/rtc if the /proc filesystem was enabled. The driver has built in
+locking so that only one process is allowed to have the /dev/rtc
+interface open at a time.
+
+A user process can monitor these interrupts by doing a read(2) or a
+select(2) on /dev/rtc -- either will block/stop the user process until
+the next interrupt is received. This is useful for things like
+reasonably high frequency data acquisition where one doesn't want to
+burn up 100% CPU by polling gettimeofday etc. etc.
+
+At high frequencies, or under high loads, the user process should check
+the number of interrupts received since the last read to determine if
+there has been any interrupt "pileup" so to speak. Just for reference, a
+typical 486-33 running a tight read loop on /dev/rtc will start to suffer
+occasional interrupt pileup (i.e. > 1 IRQ event since last read) for
+frequencies above 1024Hz. So you really should check the high bytes
+of the value you read, especially at frequencies above that of the
+normal timer interrupt, which is 100Hz.
+
+Programming and/or enabling interrupt frequencies greater than 64Hz is
+only allowed by root. This is perhaps a bit conservative, but we don't want
+an evil user generating lots of IRQs on a slow 386sx-16, where it might have
+a negative impact on performance.  Note that the interrupt handler is only
+four lines of code to minimize any possibility of this effect.
+
+The alarm and/or interrupt frequency are programmed into the RTC via
+various ioctl(2) calls as listed in ./include/linux/mc146818rtc.h
+Rather than write 50 pages describing the ioctl() and so on, it is
+perhaps more useful to include a small test program that demonstrates
+how to use them, and demonstrates the features of the driver. This is
+probably a lot more useful to people interested in writing applications
+that will be using this driver.
+
+						Paul Gortmaker
+
+-------------------- 8< ---------------- 8< -----------------------------
+
+/*
+ *	Real Time Clock Driver Test/Example Program
+ *
+ *	Compile with:
+ *		gcc -s -Wall -Wstrict-prototypes rtctest.c -o rtctest
+ *
+ *	Copyright (C) 1996, Paul Gortmaker.
+ *
+ *	Released under the GNU General Public License, version 2,
+ *	included herein by reference.
+ *
+ */
+
+#include <stdio.h>
+#include <linux/mc146818rtc.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+
+void main(void) {
+
+int i, fd, retval, irqcount = 0;
+unsigned long tmp, data;
+struct tm rtc_tm;
+
+fd = open ("/dev/rtc", O_RDONLY);
+
+if (fd ==  -1) {
+	perror("/dev/rtc");
+	exit(errno);
+}
+
+fprintf(stderr, "\n\t\t\tRTC Driver Test Example.\n\n");
+
+/* Turn on update interrupts (one per second) */
+retval = ioctl(fd, RTC_UIE_ON, 0);
+if (retval == -1) {
+	perror("ioctl");
+	exit(errno);
+}
+
+fprintf(stderr, "Counting 5 update (1/sec) interrupts from reading /dev/rtc:");
+fflush(stderr);
+for (i=1; i<6; i++) {
+	/* This read will block */
+	retval = read(fd, &data, sizeof(unsigned long));
+	if (retval == -1) {
+		perror("read");
+		exit(errno);
+	}
+	fprintf(stderr, " %d",i);
+	fflush(stderr);
+	irqcount++;
+}
+
+fprintf(stderr, "\nAgain, from using select(2) on /dev/rtc:");
+fflush(stderr);
+for (i=1; i<6; i++) {
+	struct timeval tv = {5, 0};	/* 5 second timeout on select */
+	struct fd_set readfds;
+
+	FD_ZERO(&readfds);
+	FD_SET(fd, &readfds);
+	/* The select will wait until an RTC interrupt happens. */
+	retval = select(fd+1, &readfds, NULL, NULL, &tv);
+	if (retval == -1) {
+		perror("select");
+		exit(errno);
+	}
+	/* This read won't block unlike the select-less case above. */
+	retval = read(fd, &data, sizeof(unsigned long));
+	if (retval == -1) {
+		perror("read");
+		exit(errno);
+	}
+	fprintf(stderr, " %d",i);
+	fflush(stderr);
+	irqcount++;
+}
+
+/* Turn off update interrupts */
+retval = ioctl(fd, RTC_UIE_OFF, 0);
+if (retval == -1) {
+	perror("ioctl");
+	exit(errno);
+}
+
+/* Read the RTC time/date */
+retval = ioctl(fd, RTC_RD_TIME, &rtc_tm);
+if (retval == -1) {
+	perror("ioctl");
+	exit(errno);
+}
+
+fprintf(stderr, "\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n",
+	rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
+	rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
+
+/* Set the alarm to 5 sec in the future, and check for rollover */
+rtc_tm.tm_sec += 5;
+if (rtc_tm.tm_sec >= 60) {
+	rtc_tm.tm_sec %= 60;
+	rtc_tm.tm_min++;
+}
+if  (rtc_tm.tm_min == 60) {
+	rtc_tm.tm_min = 0;
+	rtc_tm.tm_hour++;
+}
+if  (rtc_tm.tm_hour == 24)
+	rtc_tm.tm_hour = 0;
+
+retval = ioctl(fd, RTC_ALM_SET, &rtc_tm);
+if (retval == -1) {
+	perror("ioctl");
+	exit(errno);
+}
+
+/* Read the current alarm settings */
+retval = ioctl(fd, RTC_ALM_READ, &rtc_tm);
+if (retval == -1) {
+	perror("ioctl");
+	exit(errno);
+}
+
+fprintf(stderr, "Alarm time now set to %02d:%02d:%02d.\n",
+	rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
+
+/* Enable alarm interrupts */
+retval = ioctl(fd, RTC_AIE_ON, 0);
+if (retval == -1) {
+	perror("ioctl");
+	exit(errno);
+}
+
+fprintf(stderr, "Waiting 5 seconds for alarm...");
+fflush(stderr);
+/* This blocks until the alarm ring causes an interrupt */
+retval = read(fd, &data, sizeof(unsigned long));
+if (retval == -1) {
+	perror("read");
+	exit(errno);
+}
+irqcount++;
+fprintf(stderr, " okay. Alarm rang.\n");
+
+/* Disable alarm interrupts */
+retval = ioctl(fd, RTC_AIE_OFF, 0);
+if (retval == -1) {
+	perror("ioctl");
+	exit(errno);
+}
+
+/* Read periodic IRQ rate */
+retval = ioctl(fd, RTC_IRQP_READ, &tmp);
+if (retval == -1) {
+	perror("ioctl");
+	exit(errno);
+}
+fprintf(stderr, "\nPeriodic IRQ rate was %ldHz.\n", tmp);
+
+fprintf(stderr, "Counting 20 interrupts at:");
+fflush(stderr);
+
+/* The frequencies 128Hz, 256Hz, ... 8192Hz are only allowed for root. */
+for (tmp=2; tmp<=64; tmp*=2) {
+
+	retval = ioctl(fd, RTC_IRQP_SET, tmp);
+	if (retval == -1) {
+		perror("ioctl");
+		exit(errno);
+	}
+
+	fprintf(stderr, "\n%ldHz:\t", tmp);
+	fflush(stderr);
+
+	/* Enable periodic interrupts */
+	retval = ioctl(fd, RTC_PIE_ON, 0);
+	if (retval == -1) {
+		perror("ioctl");
+		exit(errno);
+	}
+
+	for (i=1; i<21; i++) {
+		/* This blocks */
+		retval = read(fd, &data, sizeof(unsigned long));
+		if (retval == -1) {
+			perror("read");
+			exit(errno);
+		}
+		fprintf(stderr, " %d",i);
+		fflush(stderr);
+		irqcount++;
+	}
+
+	/* Disable periodic interrupts */
+	retval = ioctl(fd, RTC_PIE_OFF, 0);
+	if (retval == -1) {
+		perror("ioctl");
+		exit(errno);
+	}
+}
+
+fprintf(stderr, "\n\n\t\t\t *** Test complete ***\n");
+fprintf(stderr, "\nTyping \"cat /proc/interrupts\" will show %d more events on IRQ 8.\n\n",
+								 irqcount);
+
+close(fd);
+
+} /* end main */
diff -u --recursive --new-file v1.3.88/linux/Documentation/svga.txt linux/Documentation/svga.txt
--- v1.3.88/linux/Documentation/svga.txt	Fri Apr 12 15:51:45 1996
+++ linux/Documentation/svga.txt	Mon Apr 15 11:58:23 1996
@@ -241,3 +241,5 @@
 		  original version written by hhanemaa@cs.ruu.nl, patched by
 		  Jeff Chua, rewritten by me).
 		- Screen store/restore fixed.
+2.8 (14-Apr-96)	- Previous release was not compilable without CONFIG_VIDEO_SVGA.
+		- Better recognition of text modes during mode scan.
diff -u --recursive --new-file v1.3.88/linux/MAINTAINERS linux/MAINTAINERS
--- v1.3.88/linux/MAINTAINERS	Fri Apr 12 15:51:45 1996
+++ linux/MAINTAINERS	Sun Apr 14 11:19:16 1996
@@ -99,7 +99,19 @@
 BUSLOGIC SCSI DRIVER
 P:	Leonard N. Zubkoff
 M:	Leonard N. Zubkoff <lnz@dandelion.com>
-L:	None
+L:	linux-scsi@vger.rutgers.edu
+S:	Maintained
+
+EATA-DMA SCSI DRIVER
+P:	Michael Neuffer
+M:	mike@i-Connect.Net
+L:	linux-scsi@vger.rutgers.edu
+S:	Maintained
+
+EATA-PIO SCSI DRIVER
+P:	Michael Neuffer
+M:	mike@i-Connect.Net
+L:	linux-scsi@vger.rutgers.edu
 S:	Maintained
 
 FRAME RELAY DLCI/FRAD (Sangoma drivers too)
diff -u --recursive --new-file v1.3.88/linux/Makefile linux/Makefile
--- v1.3.88/linux/Makefile	Sat Apr 13 18:22:06 1996
+++ linux/Makefile	Mon Apr 15 08:30:06 1996
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 88
+SUBLEVEL = 89
 
 ARCH = i386
 
@@ -328,9 +328,9 @@
 	
 
 distclean: mrproper
-	rm -f core `find . \( -name '*.orig' -o -name '*~' -o -name '*.bak' \
-		-o -name '#*#' -o -name '.*.orig' \) -print` TAGS
-
+	rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
+                -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
+                -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -print` TAGS
 
 backup: mrproper
 	cd .. && tar cf - linux/ | gzip -9 > backup.gz
diff -u --recursive --new-file v1.3.88/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v1.3.88/linux/arch/alpha/defconfig	Mon Apr  8 19:01:41 1996
+++ linux/arch/alpha/defconfig	Mon Apr 15 10:03:25 1996
@@ -195,6 +195,7 @@
 # CONFIG_FTAPE is not set
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
 
 #
 # Sound
diff -u --recursive --new-file v1.3.88/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c
--- v1.3.88/linux/arch/alpha/mm/init.c	Wed Apr  3 16:06:55 1996
+++ linux/arch/alpha/mm/init.c	Sun Apr 14 11:43:56 1996
@@ -62,7 +62,7 @@
 	i = MAP_NR(high_memory);
 	while (i-- > 0) {
 		total++;
-		if (mem_map[i].reserved)
+		if (PageReserved(mem_map+i))
 			reserved++;
 		else if (!mem_map[i].count)
 			free++;
@@ -121,7 +121,7 @@
 			continue;
 
 		while (nr--)
-			mem_map[pfn++].reserved = 0;
+			clear_bit(PG_reserved, &mem_map[pfn++].flags);
 	}
 
 	/* unmap the console stuff: we don't need it, and we don't want it */
@@ -152,14 +152,14 @@
 	 */
 	tmp = KERNEL_START;
 	while (tmp < start_mem) {
-		mem_map[MAP_NR(tmp)].reserved = 1;
+		set_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags);
 		tmp += PAGE_SIZE;
 	}
 
 	for (tmp = PAGE_OFFSET ; tmp < high_memory ; tmp += PAGE_SIZE) {
 		if (tmp >= MAX_DMA_ADDRESS)
-			mem_map[MAP_NR(tmp)].dma = 0;
-		if (mem_map[MAP_NR(tmp)].reserved)
+			clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
+		if (PageReserved(mem_map+MAP_NR(tmp)))
 			continue;
 		mem_map[MAP_NR(tmp)].count = 1;
 		free_page(tmp);
@@ -179,7 +179,7 @@
 	val->freeram = nr_free_pages << PAGE_SHIFT;
 	val->bufferram = buffermem;
 	while (i-- > 0)  {
-		if (mem_map[i].reserved)
+		if (PageReserved(mem_map+i))
 			continue;
 		val->totalram++;
 		if (!mem_map[i].count)
diff -u --recursive --new-file v1.3.88/linux/arch/i386/boot/video.S linux/arch/i386/boot/video.S
--- v1.3.88/linux/arch/i386/boot/video.S	Fri Apr 12 15:51:46 1996
+++ linux/arch/i386/boot/video.S	Mon Apr 15 11:58:23 1996
@@ -1,5 +1,5 @@
 !
-!	Display adapter & video mode setup, version 2.7 (09-Apr-96)
+!	Display adapter & video mode setup, version 2.8 (14-Apr-96)
 !
 !	Copyright (C) 1995, 1996 Martin Mares <mj@k332.feld.cvut.cz>
 !	Based on the original setup.S code (C) Linus Torvalds
@@ -739,6 +739,19 @@
 #endif /* CONFIG_VIDEO_RETAIN */
 
 !
+! Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
+!
+
+outidx:	out	dx,al
+	push	ax
+	mov	al,ah
+	inc	dx
+	out	dx,al
+	dec	dx
+	pop	ax
+	ret
+
+!
 ! Build the table of video modes (stored after the setup.S code at the
 ! `modelist' label. Each video mode record looks like:
 !	.word	MODE-ID		(our special mode ID (see above))
@@ -947,7 +960,12 @@
 	call	inidx
 	and	al,#0x03
 	jnz	scm2
-	mov	dx,#0x3d4		! Cursor location
+	mov	dl,#0xce		! Another set of mode bits
+	mov	al,#0x06
+	call	inidx
+	shr	al,#1
+	jc	scm2
+	mov	dl,#0xd4		! Cursor location
 	mov	al,#0x0f
 	call	inidx
 	or	al,al
@@ -1117,14 +1135,7 @@
 no_s31:	xor	bp,bp		! Detection failed
 s3rest:	movb	ah,bh
 	movb	al,#0x38	! restore old value of CRT register 0x38
-outidx:	out	dx,al		! Write to indexed VGA register
-	push	ax		! AL=index, AH=data, DX=index reg port
-	mov	al,ah
-	inc	dx
-	out	dx,al
-	dec	dx
-	pop	ax
-	ret
+	br	outidx
 
 idS3:	.byte	0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
 	.byte	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
diff -u --recursive --new-file v1.3.88/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v1.3.88/linux/arch/i386/defconfig	Wed Apr 10 17:02:23 1996
+++ linux/arch/i386/defconfig	Mon Apr 15 10:03:25 1996
@@ -156,6 +156,7 @@
 # CONFIG_FTAPE is not set
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
 
 #
 # Sound
diff -u --recursive --new-file v1.3.88/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v1.3.88/linux/arch/i386/kernel/setup.c	Wed Mar 27 08:19:28 1996
+++ linux/arch/i386/kernel/setup.c	Mon Apr 15 10:03:25 1996
@@ -199,7 +199,6 @@
 	/* request io space for devices used on all i[345]86 PC'S */
 	request_region(0x00,0x20,"dma1");
 	request_region(0x40,0x20,"timer");
-	request_region(0x70,0x10,"rtc");
 	request_region(0x80,0x20,"dma page reg");
 	request_region(0xc0,0x20,"dma2");
 	request_region(0xf0,0x10,"npu");
diff -u --recursive --new-file v1.3.88/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v1.3.88/linux/drivers/block/ide.c	Fri Apr 12 15:51:50 1996
+++ linux/drivers/block/ide.c	Mon Apr 15 08:30:06 1996
@@ -1808,7 +1808,7 @@
 	ide_drive_t *drive;
 
 	if ((drive = get_info_ptr(inode->i_rdev)) != NULL) {
-		sync_dev(inode->i_rdev);
+		fsync_dev(inode->i_rdev);
 		drive->usage--;
 #ifdef CONFIG_BLK_DEV_IDECD
 		if (drive->media == ide_cdrom) {
@@ -1822,7 +1822,7 @@
 			return;
 		}
 #endif	/* CONFIG_BLK_DEV_IDETAPE */
-		if (drive->removable) {
+		if (drive->removable && !drive->usage) {
 			byte door_unlock[] = {WIN_DOORUNLOCK,0,0,0};
 			struct request rq;
 			invalidate_buffers(inode->i_rdev);
diff -u --recursive --new-file v1.3.88/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v1.3.88/linux/drivers/block/ll_rw_blk.c	Fri Apr 12 15:51:50 1996
+++ linux/drivers/block/ll_rw_blk.c	Mon Apr 15 07:43:36 1996
@@ -346,7 +346,9 @@
 	cli();
 	req = blk_dev[major].current_request;
 	if (!req) {
-		plug_device(blk_dev + major);
+		/* MD and loop can't handle plugging without deadlocking */
+		if (major != MD_MAJOR && major != LOOP_MAJOR)
+			plug_device(blk_dev + major);
 	} else switch (major) {
 	     case IDE0_MAJOR:	/* same as HD_MAJOR */
 	     case IDE1_MAJOR:
diff -u --recursive --new-file v1.3.88/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v1.3.88/linux/drivers/char/Config.in	Wed Apr  3 16:06:55 1996
+++ linux/drivers/char/Config.in	Mon Apr 15 10:03:26 1996
@@ -59,4 +59,5 @@
      bool '   Software Watchdog' CONFIG_SOFT_WATCHDOG
   fi
 fi
+bool 'Enhanced Real Time Clock Support' CONFIG_RTC
 endmenu
diff -u --recursive --new-file v1.3.88/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v1.3.88/linux/drivers/char/Makefile	Mon Apr  8 19:01:43 1996
+++ linux/drivers/char/Makefile	Mon Apr 15 10:03:26 1996
@@ -125,6 +125,11 @@
   endif
 endif
 
+ifeq ($(CONFIG_RTC),y)
+M = y
+L_OBJS += rtc.o
+endif
+
 ifdef CONFIG_QIC02_TAPE
 L_OBJS += tpqic02.o 
 endif
diff -u --recursive --new-file v1.3.88/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v1.3.88/linux/drivers/char/mem.c	Mon Apr  8 19:01:43 1996
+++ linux/drivers/char/mem.c	Mon Apr 15 10:03:26 1996
@@ -390,7 +390,7 @@
 #if defined (CONFIG_BUSMOUSE) || defined(CONFIG_UMISC) || \
     defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
     defined (CONFIG_ATIXL_BUSMOUSE) || defined(CONFIG_SOFT_WATCHDOG) || \
-    defined (CONFIG_APM)
+    defined (CONFIG_APM) || defined (CONFIG_RTC)
 	misc_init();
 #endif
 #ifdef CONFIG_SOUND
diff -u --recursive --new-file v1.3.88/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v1.3.88/linux/drivers/char/misc.c	Mon Apr  8 19:01:43 1996
+++ linux/drivers/char/misc.c	Mon Apr 15 10:03:26 1996
@@ -66,6 +66,7 @@
 extern int ms_bus_mouse_init(void);
 extern int atixl_busmouse_init(void);
 extern void watchdog_init(void);
+extern int rtc_init(void);
 
 #ifdef CONFIG_PROC_FS
 static int proc_misc_read(char *buf, char **start, off_t offset, int len, int unused)
@@ -209,6 +210,9 @@
 #endif	
 #ifdef CONFIG_APM
 	apm_bios_init();
+#endif
+#ifdef CONFIG_RTC
+	rtc_init();
 #endif
 #endif /* !MODULE */
 	if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
diff -u --recursive --new-file v1.3.88/linux/drivers/char/rtc.c linux/drivers/char/rtc.c
--- v1.3.88/linux/drivers/char/rtc.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/char/rtc.c	Mon Apr 15 10:03:26 1996
@@ -0,0 +1,742 @@
+/*
+ *	Real Time Clock interface for Linux	
+ *
+ *	Copyright (C) 1996 Paul Gortmaker
+ *
+ *	This driver allows use of the real time clock (built into
+ *	nearly all computers) from user space. It exports the /dev/rtc
+ *	interface supporting various ioctl() and also the /proc/rtc
+ *	pseudo-file for status information.
+ *
+ *	The ioctls can be used to set the interrupt behaviour and
+ *	generation rate from the RTC via IRQ 8. Then the /dev/rtc
+ *	interface can be used to make use of these timer interrupts,
+ *	be they interval or alarm based.
+ *
+ *	The /dev/rtc interface will block on reads until an interrupt
+ *	has been received. If a RTC interrupt has already happened,
+ *	it will output an unsigned long and then block. The output value
+ *	contains the interrupt status in the low byte and the number of
+ *	interrupts since the last read in the remaining high bytes. The 
+ *	/dev/rtc interface can also be used with the select(2) call.
+ *
+ *	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.
+ *
+ *	Based on other minimal char device drivers, like Alan's
+ *	watchdog, Ted's random, etc. etc.
+ *
+ */
+
+#define RTC_VERSION		"1.04"
+
+#define RTC_IRQ 	8	/* Can't see this changing soon.	*/
+#define RTC_IO_BASE	0x70	/* Or this...				*/
+#define RTC_IO_EXTENT	0x10	/* Only really 0x70 to 0x71, but...	*/
+
+/*
+ *	Note that *all* calls to CMOS_READ and CMOS_WRITE are done with
+ *	interrupts disabled. Due to the index-port/data-port (0x70/0x71)
+ *	design of the RTC, we don't want two different things trying to
+ *	get to it at once. (e.g. the periodic 11 min sync from time.c vs.
+ *	this driver.)
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <time.h>
+
+/*
+ *	We sponge a minor off of the misc major. No need slurping
+ *	up another valuable major dev number for this.
+ */
+
+#define RTC_MINOR	135
+
+static struct wait_queue *rtc_wait;
+
+static int rtc_lseek(struct inode *inode, struct file *file, off_t offset,
+			int origin);
+
+static int rtc_read(struct inode *inode, struct file *file,
+			char *buf, int count);
+
+static int rtc_ioctl(struct inode *inode, struct file *file,
+			unsigned int cmd, unsigned long arg);
+
+static int rtc_select(struct inode *inode, struct file *file,
+			int sel_type, select_table *wait);
+
+void get_rtc_time (struct tm *rtc_tm);
+void get_rtc_alm_time (struct tm *alm_tm);
+
+inline void set_rtc_irq_bit(unsigned char bit);
+inline void mask_rtc_irq_bit(unsigned char bit);
+
+unsigned char rtc_is_updating(void);
+
+/*
+ *	Bits in rtc_status. (7 bits of room for future expansion)
+ */
+
+#define RTC_IS_OPEN		0x01	/* means /dev/rtc is in use	*/
+
+unsigned char rtc_status = 0;		/* bitmapped status byte.	*/
+unsigned long rtc_irq_data = 0;		/* our output to the world	*/
+
+unsigned char days_in_mo[] = 
+		{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+/*
+ *	A very tiny interrupt handler. It runs with SA_INTERRUPT set,
+ *	so that there is no possibility of conflicting with the
+ *	set_rtc_mmss() call that happens during some timer interrupts.
+ *	(See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.)
+ */
+
+static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/*
+	 *	Can be an alarm interrupt, update complete interrupt,
+	 *	or a periodic interrupt. We store the status in the
+	 *	low byte and the number of interrupts received since
+	 *	the last read in the remainder of rtc_irq_data.
+	 */
+
+	rtc_irq_data += 0x100;
+	rtc_irq_data &= ~0xff;
+	rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
+	wake_up_interruptible(&rtc_wait);	
+}
+
+/*
+ *	Now all the various file operations that we export.
+ */
+
+static int rtc_lseek(struct inode *inode, struct file *file, off_t offset,
+	int origin)
+{
+	return -ESPIPE;
+}
+
+static int rtc_read(struct inode *inode, struct file *file, char *buf, int count)
+{
+	struct wait_queue wait = { current, NULL };
+	int retval;
+	
+	if (count < sizeof(unsigned long))
+		return -EINVAL;
+
+	retval = verify_area(VERIFY_WRITE, buf, sizeof(unsigned long));
+	if (retval)
+		return retval;
+
+	add_wait_queue(&rtc_wait, &wait);
+
+	current->state = TASK_INTERRUPTIBLE;
+		
+	while (rtc_irq_data == 0) {
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
+			break;
+		}
+		if (current->signal & ~current->blocked) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+		schedule();
+		continue;
+	}
+
+	if (retval == 0) {
+		memcpy_tofs(buf, &rtc_irq_data, sizeof(unsigned long));
+		rtc_irq_data = 0;
+		retval = sizeof(unsigned long);
+	}
+
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&rtc_wait, &wait);
+
+	return retval;
+}
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+
+	unsigned long flags;
+
+	switch (cmd) {
+		case RTC_AIE_OFF:	/* Mask alarm int. enab. bit	*/
+		{
+			mask_rtc_irq_bit(RTC_AIE);
+			return 0;
+		}
+		case RTC_AIE_ON:	/* Allow alarm interrupts.	*/
+		{
+			set_rtc_irq_bit(RTC_AIE);
+			return 0;
+		}
+		case RTC_PIE_OFF:	/* Mask periodic int. enab. bit	*/
+		{
+			mask_rtc_irq_bit(RTC_PIE);
+			return 0;
+		}
+		case RTC_PIE_ON:	/* Allow periodic ints		*/
+		{
+			unsigned int hz;
+			unsigned char tmp;
+
+			save_flags(flags);
+			cli();
+			tmp = CMOS_READ(RTC_FREQ_SELECT) & 0x0f;
+			restore_flags(flags);
+
+			hz = (tmp ? (65536/(1<<tmp)) : 0);
+
+			/*
+			 * We don't really want Joe User enabling more
+			 * than 64Hz of interrupts on a multi-user machine.
+			 */
+			if ((hz > 64) && (!suser()))
+				return -EPERM;
+
+			set_rtc_irq_bit(RTC_PIE);
+			return 0;
+		}
+		case RTC_UIE_OFF:	/* Mask ints from RTC updates.	*/
+		{
+			mask_rtc_irq_bit(RTC_UIE);
+			return 0;
+		}
+		case RTC_UIE_ON:	/* Allow ints for RTC updates.	*/
+		{
+			set_rtc_irq_bit(RTC_UIE);
+			return 0;
+		}
+		case RTC_ALM_READ:	/* Read the present alarm time */
+		{
+			/*
+			 * This returns a struct tm. Reading >= 0xc0 means
+			 * "don't care" or "match all". Only the tm_hour,
+			 * tm_min, and tm_sec values are filled in.
+			 */
+			int retval;
+			struct tm alm_tm;
+
+			retval = verify_area(VERIFY_WRITE, (struct tm*)arg, sizeof(struct tm));
+			if (retval != 0 )
+				return retval;
+
+			get_rtc_alm_time(&alm_tm);
+
+			memcpy_tofs((struct tm*)arg, &alm_tm, sizeof(struct tm));
+			
+			return 0;
+		}
+		case RTC_ALM_SET:	/* Store a time into the alarm */
+		{
+			/*
+			 * This expects a struct tm. Writing 0xff means
+			 * "don't care" or "match all". Only the tm_hour,
+			 * tm_min and tm_sec are used.
+			 */
+			int retval;
+			unsigned char hrs, min, sec;
+			struct tm alm_tm;
+
+			retval = verify_area(VERIFY_READ, (struct tm*)arg, sizeof(struct tm));
+			if (retval != 0 )
+				return retval;
+
+			memcpy_fromfs(&alm_tm, (struct tm*)arg, sizeof(struct tm));
+
+			hrs = alm_tm.tm_hour;
+			min = alm_tm.tm_min;
+			sec = alm_tm.tm_sec;
+
+			if (hrs >= 24)
+				hrs = 0xff;
+
+			if (min >= 60)
+				min = 0xff;
+
+			if (sec >= 60)
+				sec = 0xff;
+
+			save_flags(flags);
+			cli();
+			if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ||
+							RTC_ALWAYS_BCD)
+			{
+				BIN_TO_BCD(sec);
+				BIN_TO_BCD(min);
+				BIN_TO_BCD(hrs);
+			}
+			CMOS_WRITE(hrs, RTC_HOURS_ALARM);
+			CMOS_WRITE(min, RTC_MINUTES_ALARM);
+			CMOS_WRITE(sec, RTC_SECONDS_ALARM);
+			restore_flags(flags);
+
+			return 0;
+		}
+		case RTC_RD_TIME:	/* Read the time/date from RTC	*/
+		{
+			int retval;
+			struct tm rtc_tm;
+			
+			retval = verify_area(VERIFY_WRITE, (struct tm*)arg, sizeof(struct tm));
+			if (retval !=0 )
+				return retval;
+
+			get_rtc_time(&rtc_tm);
+			memcpy_tofs((struct tm*)arg, &rtc_tm, sizeof(struct tm));
+			return 0;
+		}
+		case RTC_SET_TIME:	/* Set the RTC */
+		{
+			int retval;
+			struct tm rtc_tm;
+			unsigned char mon, day, hrs, min, sec, leap_yr;
+			unsigned char save_control, save_freq_select;
+			unsigned int yrs;
+			unsigned long flags;
+			
+			if (!suser())
+				return -EPERM;
+
+			retval = verify_area(VERIFY_READ, (struct tm*)arg, sizeof(struct tm));
+			if (retval !=0 )
+				return retval;
+
+			memcpy_fromfs(&rtc_tm, (struct tm*)arg, sizeof(struct tm));
+
+			yrs = rtc_tm.tm_year + 1900;
+			mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
+			day = rtc_tm.tm_mday;
+			hrs = rtc_tm.tm_hour;
+			min = rtc_tm.tm_min;
+			sec = rtc_tm.tm_sec;
+
+			if ((yrs < 1970) || (yrs > 2069))
+				return -EINVAL;
+
+			leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
+
+			if ((mon > 12) || (day == 0))
+				return -EINVAL;
+
+			if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
+				return -EINVAL;
+			
+			if ((hrs >= 24) || (min >= 60) || (sec >= 60))
+				return -EINVAL;
+
+			if (yrs >= 2000)
+				yrs -= 2000;	/* RTC (0, 1, ... 69) */
+			else
+				yrs -= 1900;	/* RTC (70, 71, ... 99) */
+
+			save_flags(flags);
+			cli();
+			if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ||
+							RTC_ALWAYS_BCD)
+			{
+				BIN_TO_BCD(sec);
+				BIN_TO_BCD(min);
+				BIN_TO_BCD(hrs);
+				BIN_TO_BCD(day);
+				BIN_TO_BCD(mon);
+				BIN_TO_BCD(yrs);
+			}
+
+			save_control = CMOS_READ(RTC_CONTROL);
+			CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+			save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
+			CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+			CMOS_WRITE(yrs, RTC_YEAR);
+			CMOS_WRITE(mon, RTC_MONTH);
+			CMOS_WRITE(day, RTC_DAY_OF_MONTH);
+			CMOS_WRITE(hrs, RTC_HOURS);
+			CMOS_WRITE(min, RTC_MINUTES);
+			CMOS_WRITE(sec, RTC_SECONDS);
+
+			CMOS_WRITE(save_control, RTC_CONTROL);
+			CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+			restore_flags(flags);
+			return 0;
+		}
+		case RTC_IRQP_READ:	/* Read the periodic IRQ rate.	*/
+		{
+			unsigned long hz;
+			int retval;
+
+			retval = verify_area(VERIFY_WRITE, (unsigned long*)arg, sizeof(unsigned long));
+			if (retval != 0)
+				return retval;
+
+			save_flags(flags);
+			cli();
+			retval = CMOS_READ(RTC_FREQ_SELECT) & 0x0f;
+			restore_flags(flags);
+			hz = (retval ? (65536/(1<<retval)) : 0);
+			memcpy_tofs((unsigned long*)arg, &hz, sizeof(unsigned long));
+			return 0;
+		}
+		case RTC_IRQP_SET:	/* Set periodic IRQ rate.	*/
+		{
+			int tmp = 0;
+			unsigned char val;
+
+			/* 
+			 * The max we can do is 8192Hz.
+			 */
+			if (arg > 8192)
+				return -EINVAL;
+			/*
+			 * We don't really want Joe User generating more
+			 * than 64Hz of interrupts on a multi-user machine.
+			 */
+			if ((arg > 64) && (!suser()))
+				return -EPERM;
+
+			while (arg > (1<<tmp))
+				tmp++;
+
+			/*
+			 * Check that the input was really a power of 2.
+			 */
+			if ((arg != 0) && (arg != (1<<tmp)))
+				return -EINVAL;
+
+			save_flags(flags);
+			cli();
+			val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
+
+			if (arg == 0) {
+				CMOS_WRITE(val, RTC_FREQ_SELECT);
+				restore_flags(flags);
+				return 0;
+			}
+
+			val |= (16 - tmp);
+			CMOS_WRITE(val, RTC_FREQ_SELECT);
+			restore_flags(flags);
+			return 0;
+		}
+		default:
+			return -EINVAL;
+	}
+}
+
+/*
+ *	We enforce only one user at a time here with the open/close.
+ *	Also clear the previous interrupt data on an open, and clean
+ *	up things on a close.
+ */
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+
+	if(rtc_status & RTC_IS_OPEN)
+		return -EBUSY;
+
+	rtc_status |= RTC_IS_OPEN;
+	rtc_irq_data = 0;
+	return 0;
+}
+
+static void rtc_release(struct inode *inode, struct file *file)
+{
+
+	/*
+	 * Turn off all interrupts once the device is no longer
+	 * in use, and clear the data.
+	 */
+
+	unsigned char tmp;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	tmp = CMOS_READ(RTC_CONTROL);
+	tmp &=  ~RTC_PIE;
+	tmp &=  ~RTC_AIE;
+	tmp &=  ~RTC_UIE;
+	CMOS_WRITE(tmp, RTC_CONTROL);
+	CMOS_READ(RTC_INTR_FLAGS);
+	restore_flags(flags);
+	rtc_irq_data = 0;
+	rtc_status &= ~RTC_IS_OPEN;
+}
+
+static int rtc_select(struct inode *inode, struct file *file,
+			int sel_type, select_table *wait)
+{
+	if (sel_type == SEL_IN) {
+		if (rtc_irq_data != 0)
+			return 1;
+		select_wait(&rtc_wait, wait);
+	}
+	return 0;
+}
+
+/*
+ *	The various file operations we support.
+ */
+
+static struct file_operations rtc_fops = {
+	rtc_lseek,
+	rtc_read,
+	NULL,		/* No write */
+	NULL,		/* No readdir */
+	rtc_select,
+	rtc_ioctl,
+	NULL,		/* No mmap */
+	rtc_open,
+	rtc_release
+};
+
+static struct miscdevice rtc_dev=
+{
+	RTC_MINOR,
+	"rtc",
+	&rtc_fops
+};
+
+int rtc_init(void)
+{
+	printk("Real Time Clock Driver v%s\n", RTC_VERSION);
+	if(request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL))
+	{
+		/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
+		printk("rtc: IRQ %d is not free.\n", RTC_IRQ);
+		return -EIO;
+	}
+	misc_register(&rtc_dev);
+	/* Check region? Naaah! Just snarf it up. */
+	request_region(RTC_IO_BASE, RTC_IO_EXTENT, "rtc");
+	rtc_wait = NULL;
+	return 0;
+}
+
+/*
+ *	Info exported via "/proc/rtc".
+ */
+
+int get_rtc_status(char *buf)
+{
+	char *p;
+	struct tm tm;
+	unsigned char freq, batt, ctrl;
+	unsigned long flags;
+
+	save_flags(flags);
+	freq = CMOS_READ(RTC_FREQ_SELECT) & 0x0F;
+	batt = CMOS_READ(RTC_VALID) & RTC_VRT;
+	ctrl = CMOS_READ(RTC_CONTROL);
+	restore_flags(flags);
+
+	p = buf;
+	p += sprintf(p, "Real Time Clock Status:\n");
+
+	get_rtc_time(&tm);
+
+	/*
+	 * There is no way to tell if the luser has the RTC set for local
+	 * time or for Universal Standard Time (GMT). Probably local though.
+	 */
+	p += sprintf(p, "\tRTC reports %02d:%02d:%02d of %d-%d-%d.\n",
+		tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_mday, 
+		tm.tm_mon + 1, tm.tm_year + 1900);
+
+	get_rtc_alm_time(&tm);
+
+	/*
+	 * We implicitly assume 24hr mode here. Alarm values >= 0xc0 will
+	 * match any value for that particular field. Values that are
+	 * greater than a valid time, but less than 0xc0 shouldn't appear.
+	 */
+	p += sprintf(p, "\tAlarm set to match: ");
+	if (tm.tm_hour <= 24)
+		p += sprintf(p, "hour=%d, ", tm.tm_hour);
+	else
+		p += sprintf(p, "hour=any, ");
+	if (tm.tm_min <= 59)
+		p += sprintf(p, "min=%d, ", tm.tm_min);
+	else
+		p += sprintf(p, "min=any, ");
+	if (tm.tm_sec <= 59)
+		p += sprintf(p, "sec=%d.\n", tm.tm_sec);
+	else
+		p += sprintf(p, "sec=any.\n");
+
+	p += sprintf(p, "\tMisc. settings: daylight=%s; BCD=%s; 24hr=%s; Sq-Wave=%s.\n",
+		((ctrl & RTC_DST_EN) ? "yes" : "no" ),
+		((ctrl & RTC_DM_BINARY) ? "no" : "yes" ),
+		((ctrl & RTC_24H) ? "yes" : "no" ),
+		((ctrl & RTC_SQWE) ? "yes" : "no" ));
+
+	p += sprintf(p, "\tInterrupt for: alarm=%s; update=%s; periodic=%s.\n",
+		((ctrl & RTC_AIE) ? "yes" : "no" ),
+		((ctrl & RTC_UIE) ? "yes" : "no" ),
+		((ctrl & RTC_PIE) ? "yes" : "no" ));
+
+	p += sprintf(p, "\tPeriodic interrupt rate set to %dHz.\n",
+		(freq ? (65536/(1<<freq)) : 0));
+
+	p += sprintf(p, "\tRTC reports that CMOS battery is %s.\n",
+		(batt ? "okay" : "dead"));
+
+	return  p - buf;
+}
+
+/*
+ * Returns true if a clock update is in progress
+ */
+inline unsigned char rtc_is_updating(void)
+{
+	unsigned long flags;
+	unsigned char uip;
+
+	save_flags(flags);
+	uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
+	restore_flags(flags);
+	return uip;
+}
+
+void get_rtc_time(struct tm *rtc_tm)
+{
+
+	unsigned long flags, uip_watchdog = jiffies;
+	unsigned char ctrl;
+
+	/*
+	 * read RTC once any update in progress is done. The update
+	 * can take just over 2ms. We wait 10 to 20ms. There is no need to
+	 * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
+	 * If you need to know *exactly* when a second has started, enable
+	 * periodic update complete interrupts, (via ioctl) and then 
+	 * immediately read /dev/rtc which will block until you get the IRQ.
+	 * Once the read clears, read the RTC time (again via ioctl). Easy.
+	 */
+
+	if (rtc_is_updating() != 0)
+		while (jiffies - uip_watchdog < 2*HZ/100)
+			barrier();
+
+	/*
+	 * Only the values that we read from the RTC are set. We leave
+	 * tm_wday, tm_yday and tm_isdst untouched. Even though the
+	 * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
+	 * by the RTC when initially set to a non-zero value.
+	 */
+	save_flags(flags);
+	cli();
+	rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
+	rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
+	rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
+	rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
+	rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
+	rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
+	ctrl = CMOS_READ(RTC_CONTROL);
+	restore_flags(flags);
+
+	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+	{
+		BCD_TO_BIN(rtc_tm->tm_sec);
+		BCD_TO_BIN(rtc_tm->tm_min);
+		BCD_TO_BIN(rtc_tm->tm_hour);
+		BCD_TO_BIN(rtc_tm->tm_mday);
+		BCD_TO_BIN(rtc_tm->tm_mon);
+		BCD_TO_BIN(rtc_tm->tm_year);
+	}
+
+	/*
+	 * Account for differences between how the RTC uses the values
+	 * and how they are defined in a struct tm;
+	 */
+	if (rtc_tm->tm_year <= 69)
+		rtc_tm->tm_year += 100;
+
+	rtc_tm->tm_mon--;
+}
+
+void get_rtc_alm_time(struct tm *alm_tm)
+{
+	unsigned long flags;
+	unsigned char ctrl;
+
+	/*
+	 * Only the values that we read from the RTC are set. That
+	 * means only tm_hour, tm_min, and tm_sec.
+	 */
+	save_flags(flags);
+	cli();
+	alm_tm->tm_sec = CMOS_READ(RTC_SECONDS_ALARM);
+	alm_tm->tm_min = CMOS_READ(RTC_MINUTES_ALARM);
+	alm_tm->tm_hour = CMOS_READ(RTC_HOURS_ALARM);
+	ctrl = CMOS_READ(RTC_CONTROL);
+	restore_flags(flags);
+
+	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+	{
+		BCD_TO_BIN(alm_tm->tm_sec);
+		BCD_TO_BIN(alm_tm->tm_min);
+		BCD_TO_BIN(alm_tm->tm_hour);
+	}
+}
+
+/*
+ * Used to disable/enable interrupts for any one of UIE, AIE, PIE.
+ * Rumour has it that if you frob the interrupt enable/disable
+ * bits in RTC_CONTROL, you should read RTC_INTR_FLAGS, to
+ * ensure you actually start getting interrupts. Probably for
+ * compatibility with older/broken chipset RTC implementations.
+ * We also clear out any old irq data after an ioctl() that
+ * meddles the interrupt enable/disable bits.
+ */
+inline void mask_rtc_irq_bit(unsigned char bit)
+{
+	unsigned char val;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	val = CMOS_READ(RTC_CONTROL);
+	val &=  ~bit;
+	CMOS_WRITE(val, RTC_CONTROL);
+	CMOS_READ(RTC_INTR_FLAGS);
+	restore_flags(flags);
+	rtc_irq_data = 0;
+}
+
+inline void set_rtc_irq_bit(unsigned char bit)
+{
+	unsigned char val;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	val = CMOS_READ(RTC_CONTROL);
+	val |= bit;
+	CMOS_WRITE(val, RTC_CONTROL);
+	CMOS_READ(RTC_INTR_FLAGS);
+	restore_flags(flags);
+	rtc_irq_data = 0;
+}
+
diff -u --recursive --new-file v1.3.88/linux/drivers/net/dlci.c linux/drivers/net/dlci.c
--- v1.3.88/linux/drivers/net/dlci.c	Wed Apr 10 17:02:24 1996
+++ linux/drivers/net/dlci.c	Sun Apr 14 11:43:55 1996
@@ -5,10 +5,21 @@
  *		interfaces.  Requires 'dlcicfg' program to create usable 
  *		interfaces, the initial one, 'dlci' is for IOCTL use only.
  *
- * Version:	@(#)dlci.c	0.15	31 Mar 1996
+ * Version:	@(#)dlci.c	0.20	13 Apr 1996
  *
  * Author:	Mike McLagan <mike.mclagan@linux.org>
  *
+ * Changes:
+ *
+ *		0.15	Mike Mclagan	Packet freeing, bug in kmalloc call
+ *					DLCI_RET handling
+ *
+ *		0.20	Mike McLagan	More conservative on which packets
+ *					are returned for retry and whic are
+ *					are dropped.  If DLCI_RET_DROP is
+ *					returned from the FRAD, the packet is
+ *				 	sent back to Linux for re-transmission
+ *
  *		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
@@ -41,7 +52,7 @@
 #include <net/sock.h>
 
 static const char *devname = "dlci";
-static const char *version = "DLCI driver v0.15, 31 Mar 1996, mike.mclagan@linux.org";
+static const char *version = "DLCI driver v0.20, 13 Apr 1996, mike.mclagan@linux.org";
 
 static struct device *open_dev[CONFIG_DLCI_COUNT];
 
@@ -240,20 +251,26 @@
       {
          case DLCI_RET_OK:
             dlp->stats.tx_packets++;
+            ret = 0;
             break;
 
          case DLCI_RET_ERR:
             dlp->stats.tx_errors++;
+            ret = 0;
             break;
 
          case DLCI_RET_DROP:
             dlp->stats.tx_dropped++;
+            ret = 1;
             break;
       }
 
       /* Alan Cox recommends always returning 0, and always freeing the packet */
-      ret = 0;
-      dev_kfree_skb(skb, FREE_WRITE);
+      /* experience suggest a slightly more conservative approach */
+
+      if (!ret)
+         dev_kfree_skb(skb, FREE_WRITE);
+
       dev->tbusy = 0;
    }
 
@@ -406,6 +423,10 @@
 
    if (!get)
    {
+      err = verify_area(VERIFY_READ, conf, sizeof(struct dlci_conf));
+      if (err)
+         return(err);
+
       memcpy_fromfs(&config, conf, sizeof(struct dlci_conf));
       if (config.flags & ~DLCI_VALID_FLAGS)
          return(-EINVAL);
@@ -418,7 +439,13 @@
       return(err);
 
    if (get)
+   {
+      err = verify_area(VERIFY_WRITE, conf, sizeof(struct dlci_conf));
+      if (err)
+         return(err);
+
       memcpy_tofs(conf, &dlp->config, sizeof(struct dlci_conf));
+   }
 
    return(0);
 }
diff -u --recursive --new-file v1.3.88/linux/drivers/net/sdla.c linux/drivers/net/sdla.c
--- v1.3.88/linux/drivers/net/sdla.c	Fri Apr 12 15:51:56 1996
+++ linux/drivers/net/sdla.c	Sun Apr 14 11:43:55 1996
@@ -1,25 +1,32 @@
 /*
- * SDLA      An implementation of a driver for the Sangoma S502/S508 series
- *           multi-protocol PC interface card.  Initial offering is with 
- *           the DLCI driver, providing Frame Relay support for linux.
+ * SDLA		An implementation of a driver for the Sangoma S502/S508 series
+ *		multi-protocol PC interface card.  Initial offering is with 
+ *		the DLCI driver, providing Frame Relay support for linux.
  *
- *           Global definitions for the Frame relay interface.
+ *		Global definitions for the Frame relay interface.
  *
- * Version:  @(#)sdla.c   0.10   23 Mar 1996
+ * Version:	@(#)sdla.c   0.20	13 Apr 1996
  *
- * Credits:  Sangoma Technologies, for the use of 2 cards for an extended
- *                                 period of time.
- *           David Mandelstam <dm@sangoma.com> for getting me started on 
- *                            this project, and incentive to complete it.
- *           Gene Kozen <74604.152@compuserve.com> for providing me with
- *                      important information about the cards.
+ * Credits:	Sangoma Technologies, for the use of 2 cards for an extended
+ *			period of time.
+ *		David Mandelstam <dm@sangoma.com> for getting me started on 
+ *			this project, and incentive to complete it.
+ *		Gene Kozen <74604.152@compuserve.com> for providing me with
+ *			important information about the cards.
  *
- * Author:   Mike McLagan <mike.mclagan@linux.org>
+ * Author:	Mike McLagan <mike.mclagan@linux.org>
  *
- *           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.
+ * Changes:
+ *		0.15	Mike McLagan	Improved error handling, packet dropping
+ *		0.20	Mike McLagan	New transmit/receive flags for config
+ *					If in FR mode, don't accept packets from
+ *					non-DLCI devices.
+ *
+ *
+ *		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.
  */
 
 #include <linux/module.h>
@@ -49,7 +56,7 @@
 
 #include <linux/sdla.h>
 
-static const char* version = "SDLA driver v0.10, 23 Mar 1996, mike.mclagan@linux.org";
+static const char* version = "SDLA driver v0.20, 13 Apr 1996, mike.mclagan@linux.org";
 
 static const char* devname = "sdla";
 
@@ -78,14 +85,9 @@
    temp = buf;
    while(len)
    {
-      offset = addr & 0x1FFF;
-      if (offset + len > 0x2000)
-         bytes = 0x2000 - offset;
-      else
-         bytes = len;
-
-      base = (void *) dev->mem_start;
-      base += offset;
+      offset = addr & SDLA_ADDR_MASK;
+      bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
+      base = (void *) (dev->mem_start + offset);
 
       save_flags(flags);
       cli();
@@ -108,14 +110,9 @@
    temp = buf;
    while(len)
    {
-      offset = addr & 0x1FFF;
-      if (offset + len > 0x2000)
-         bytes = 0x2000 - offset;
-      else
-         bytes = len;
-
-      base = (void *) dev->mem_start;
-      base += offset;
+      offset = addr & SDLA_ADDR_MASK;
+      bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len;
+      base = (void *) (dev->mem_start + offset);
 
       save_flags(flags);
       cli();
@@ -133,30 +130,24 @@
 {
    unsigned long flags;
    char          *base;
-   int           offset, len, addr, bytes;
+   int           len, addr, bytes;
 
    len = 65536;
    addr = 0;
+   bytes = SDLA_WINDOW_SIZE;
+   base = (void *) dev->mem_start;
+
+   save_flags(flags);
+   cli();
    while(len)
    {
-      offset = addr & 0x1FFF;
-      if (offset + len > 0x2000)
-         bytes = offset + len - 0x2000;
-      else
-         bytes = len;
-
-      base = (void *) dev->mem_start;
-      base += offset;
-
-      save_flags(flags);
-      cli();
       SDLA_WINDOW(dev, addr);
       memset(base, 0, bytes);
-      restore_flags(flags);
 
       addr += bytes;
       len  -= bytes;
    }
+   restore_flags(flags);
 }
 
 static char sdla_byte(struct device *dev, int addr)
@@ -164,8 +155,7 @@
    unsigned long flags;
    char          byte, *temp;
 
-   temp = (void *) dev->mem_start;
-   temp += addr & 0x1FFF;
+   temp = (void *) (dev->mem_start + (addr & SDLA_ADDR_MASK));
 
    save_flags(flags);
    cli();
@@ -250,7 +240,7 @@
    done = jiffies + jiffs;
 
    temp = (void *)dev->mem_start;
-   temp += z80_addr & 0x1FFF;
+   temp += z80_addr & SDLA_ADDR_MASK;
 
    resp = ~resp1;
    while ((jiffies < done) && (resp != resp1) && (!resp2 || (resp != resp2)))
@@ -393,18 +383,25 @@
          printk(KERN_ERR "%s: Command timed out!\n", dev->name);
          break;
 
+      case SDLA_RET_BUF_OVERSIZE:
+         printk(KERN_INFO "%s: Bc/CIR overflow, acceptable size is %i\n", dev->name, len);
+         break;
+
+      case SDLA_RET_BUF_TOO_BIG:
+         printk(KERN_INFO "%s: Buffer size over specified max of %i\n", dev->name, len);
+         break;
+
       case SDLA_RET_CHANNEL_INACTIVE:
       case SDLA_RET_DLCI_INACTIVE:
-      case SDLA_RET_NO_BUFF:
+      case SDLA_RET_CIR_OVERFLOW:
+      case SDLA_RET_NO_BUFS:
          if (cmd == SDLA_INFORMATION_WRITE)
             break;
 
       default: 
-         /*
-          * Further processing could be done here 
-          * printk(KERN_DEBUG "%s: Unhandled return code 0x%2.2X\n", dev->name, ret);
-          *
-          */
+         printk(KERN_DEBUG "%s: Cmd 0x%2.2X generated return code 0x%2.2X\n", dev->name, cmd, ret);
+/* Further processing could be done here */
+         break;
    }
 }
 
@@ -416,16 +413,14 @@
    struct sdla_cmd          *cmd_buf;
    unsigned long            pflags;
    int                      jiffs, ret, waiting, len;
-   long                     temp, window;
+   long                     window;
 
    flp = dev->priv;
 
    window = flp->type == SDLA_S508 ? SDLA_508_CMD_BUF : SDLA_502_CMD_BUF;
-   temp = (int) dev->mem_start;
-   temp += window & 0x1FFF;
-   cmd_buf = (struct sdla_cmd *)temp;
+   cmd_buf = (struct sdla_cmd *)(dev->mem_start + (window & SDLA_ADDR_MASK));
    ret = 0;
-   jiffs = jiffies + HZ / 2;  /* 1/2 second timeout */
+   jiffs = jiffies + HZ;  /* 1 second is plenty */
    save_flags(pflags);
    cli();
    SDLA_WINDOW(dev, window);
@@ -445,7 +440,7 @@
    len = 0;
    while (waiting && (jiffies <= jiffs))
    {
-      if (waiting++ % 4) 
+      if (waiting++ % 3) 
       {
          save_flags(pflags);
          cli();
@@ -462,13 +457,18 @@
       SDLA_WINDOW(dev, window);
       ret = cmd_buf->retval;
       len = cmd_buf->length;
-      if (outbuf && len)
+      if (outbuf && outlen)
       {
          *outlen = *outlen >= len ? len : *outlen;
-         memcpy(outbuf, cmd_buf->data, *outlen);
+
+         if (*outlen)
+            memcpy(outbuf, cmd_buf->data, *outlen);
       }
+
+      /* This is a local copy that's used for error handling */
       if (ret)
-         memcpy(&status, cmd_buf->data, len);
+         memcpy(&status, cmd_buf->data, len > sizeof(status) ? sizeof(status) : len);
+
       restore_flags(pflags);
    }
    else
@@ -521,6 +521,9 @@
       if (flp->master[i] == master)
          break;
 
+   if (i == CONFIG_DLCI_MAX)
+      return(-ENODEV);
+
    flp->dlci[i] = -abs(flp->dlci[i]);
 
    if (slave->start && (flp->config.station == FRAD_STATION_NODE))
@@ -598,6 +601,7 @@
    struct frad_local *flp;
    struct frad_local *dlp;
    int               i;
+   short             len, ret;
 
    flp = slave->priv;
 
@@ -609,11 +613,18 @@
       return(-ENODEV);
 
    dlp = master->priv;
+
+   ret = SDLA_RET_OK;
+   len = sizeof(struct dlci_conf);
    if (slave->start)
-      sdla_cmd(slave, SDLA_SET_DLCI_CONFIGURATION, flp->dlci[i], 0,  
-                  &dlp->config, sizeof(struct dlci_conf) - 4 * sizeof(short), NULL, NULL);
+      if (get)
+         ret = sdla_cmd(slave, SDLA_READ_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,  
+                     NULL, 0, &dlp->config, &len);
+      else
+         ret = sdla_cmd(slave, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0,  
+                     &dlp->config, sizeof(struct dlci_conf) - 4 * sizeof(short), NULL, NULL);
 
-   return(0);
+   return(ret == SDLA_RET_OK ? 0 : -EIO);
 }
 
 /**************************
@@ -622,6 +633,7 @@
  *
  **************************/
 
+/* NOTE: the DLCI driver deals with freeing the SKB!! */
 static int sdla_transmit(struct sk_buff *skb, struct device *dev)
 {
    struct frad_local *flp;
@@ -643,6 +655,31 @@
       printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
    else
    {
+ 
+      /*
+       * stupid GateD insists on setting up the multicast router thru us
+       * and we're ill equipped to handle a non Frame Relay packet at this
+       * time!
+       */
+
+      switch (dev->type)
+      {
+         case ARPHRD_FRAD:
+            if (skb->dev->type != ARPHRD_DLCI)
+            {
+               printk(KERN_WARNING "%s: FRAD module accepts packets from DLCI ONLY!\n", dev->name);
+               dev_kfree_skb(skb, FREE_WRITE);
+               return(0);
+            }
+            break;
+
+         default:
+            printk(KERN_WARNING "%s: unknown firmware type 0x%4.4X\n", dev->name, dev->type);
+            dev_kfree_skb(skb, FREE_WRITE);
+            return(0);
+      }
+
+      /* this is frame specific, but till there's a PPP module, it's the default */
       switch (flp->type)
       {
          case SDLA_S502A:
@@ -658,7 +695,7 @@
                save_flags(flags); 
                cli();
                SDLA_WINDOW(dev, addr);
-               pbuf = (void *)(((int) dev->mem_start) + (addr & 0x1FFF));
+               pbuf = (void *)(((int) dev->mem_start) + (addr & SDLA_ADDR_MASK));
 
                sdla_write(dev, pbuf->buf_addr, skb->data, skb->len);
 
@@ -673,17 +710,21 @@
       {
          case SDLA_RET_OK:
             flp->stats.tx_packets++;
-            ret = 0;
+            ret = DLCI_RET_OK;
             break;
  
+         case SDLA_RET_CIR_OVERFLOW:
+         case SDLA_RET_BUF_OVERSIZE:
+         case SDLA_RET_NO_BUFS:
+            flp->stats.tx_dropped++;
+            ret = DLCI_RET_DROP;
+            break;
+
          default:
             flp->stats.tx_errors++;
-            ret = 1;
+            ret = DLCI_RET_ERR;
+            break;
       }
-
-      /* per Alan Cox, we can drop the packet on the floor if it doesn't go */
-      dev_kfree_skb(skb, FREE_WRITE);
-
       dev->tbusy = 0;
    }
    return(ret);
@@ -701,17 +742,18 @@
    struct buf_entry  *pbuf;
 
    unsigned long     flags;
-   int               i, received, success, addr;
-   short             dlci, len, split;
-   char              bogus;
+   int               i, received, success, addr, buf_base, buf_top;
+   short             dlci, len, len2, split;
 
    flp = dev->priv;
-   bogus = 0;
-   success = 0;
-   received = 0;
-   addr = 0;
+   success = 1;
+   received = addr = buf_top = buf_base = 0;
+   len = dlci = 0;
    skb = NULL;
    master = NULL;
+   cmd = NULL;
+   pbufi = NULL;
+   pbuf = NULL;
 
    save_flags(flags);
    cli();
@@ -720,93 +762,89 @@
    {
       case SDLA_S502A:
       case SDLA_S502E:
-         cmd = (void *) (dev->mem_start + (SDLA_502_RCV_BUF & 0x1FFF));
+         cmd = (void *) (dev->mem_start + (SDLA_502_RCV_BUF & SDLA_ADDR_MASK));
          SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
-         if (!cmd->opp_flag)
+         success = cmd->opp_flag;
+         if (!success)
             break;
 
          dlci = cmd->dlci;
          len = cmd->length;
-
-         for (i=0;i<CONFIG_DLCI_MAX;i++)
-            if (flp->dlci[i] == dlci)
-               break;
-
-         if (i == CONFIG_DLCI_MAX)
-         {
-            printk(KERN_NOTICE "%s: Received packet from invalid DLCI %i, ignoring.", dev->name, dlci);
-            flp->stats.rx_errors++;
-            cmd->opp_flag = 0;
-            break;
-         }
-
-         master = flp->master[i];
-         skb = dev_alloc_skb(len);
-         if (skb == NULL) 
-         {
-            printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
-            flp->stats.rx_dropped++;
-            cmd->opp_flag = 0;
-            break;
-         }
-
-         /* pick up the data */
-         sdla_read(dev, dev->mem_start + ((SDLA_502_RCV_BUF + SDLA_502_DATA_OFS) & 0x1FFF), skb_put(skb,len), len);
-         cmd->opp_flag = 0;
-         success = 1;
          break;
 
       case SDLA_S508:
-         pbufi = (void *) (dev->mem_start + (SDLA_508_RXBUF_INFO & 0x1FFF));
+         pbufi = (void *) (dev->mem_start + (SDLA_508_RXBUF_INFO & SDLA_ADDR_MASK));
          SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
-         pbuf = (void *) (dev->mem_start + ((pbufi->rse_base + flp->buffer * sizeof(struct buf_entry)) & 0x1FFF));
-         if (!pbuf->opp_flag)
+         pbuf = (void *) (dev->mem_start + ((pbufi->rse_base + flp->buffer * sizeof(struct buf_entry)) & SDLA_ADDR_MASK));
+         success = pbuf->opp_flag;
+         if (!success)
             break;
 
+         buf_top = pbufi->buf_top;
+         buf_base = pbufi->buf_base;
          dlci = pbuf->dlci;
          len = pbuf->length;
          addr = pbuf->buf_addr;
+         break;
+   }
 
-         for (i=0;i<CONFIG_DLCI_MAX;i++)
-            if (flp->dlci[i] == dlci)
-               break;
-
-         if (i == CONFIG_DLCI_MAX)
-         {
-            printk(KERN_NOTICE "%s: Received packet from invalid DLCI %i, ignoring.", dev->name, dlci);
-            flp->stats.rx_errors++;
-            pbuf->opp_flag = 0;
+   /* common code, find the DLCI and get the SKB */
+   if (success)
+   {
+      for (i=0;i<CONFIG_DLCI_MAX;i++)
+         if (flp->dlci[i] == dlci)
             break;
-         }
 
-         master = flp->master[i];
-         skb = dev_alloc_skb(len);
-         if (skb == NULL) 
-         {
-            printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
-            flp->stats.rx_dropped++;
-            pbuf->opp_flag = 0;
-            break;
-         }
+      if (i == CONFIG_DLCI_MAX)
+      {
+         printk(KERN_NOTICE "%s: Recieved packet from invalid DLCI %i, ignoring.", dev->name, dlci);
+         flp->stats.rx_errors++;
+         success = 0;
+      }
+   }
 
-         /* is this buffer split off the end of the internal ring buffer */
-         split = addr + len > pbufi->buf_top + 1 ? pbufi->buf_top - addr + 1 : 0;
-         len -= split;
-
-         /* lets get the data */
-         sdla_read(dev, addr, skb_put(skb, len), len);
-         if (split)
+   if (success)
+   {
+      master = flp->master[i];
+      skb = dev_alloc_skb(len + sizeof(struct frhdr));
+      if (skb == NULL) 
+      {
+         printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+         flp->stats.rx_dropped++; 
+         success = 0;
+      }
+      else
+         skb_reserve(skb, sizeof(struct frhdr));
+   }
+
+   /* pick up the data */
+   switch (flp->type)
+   {
+      case SDLA_S502A:
+      case SDLA_S502E:
+         if (success)
+            sdla_read(dev, SDLA_502_RCV_BUF + SDLA_502_DATA_OFS, skb_put(skb,len), len);
+
+         SDLA_WINDOW(dev, SDLA_502_RCV_BUF);
+         cmd->opp_flag = 0;
+         break;
+
+      case SDLA_S508:
+         if (success)
          {
-            SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
-            sdla_read(dev, pbufi->buf_base, skb_put(skb, split), split);
+            /* is this buffer split off the end of the internal ring buffer */
+            split = addr + len > buf_top + 1 ? len - (buf_top - addr + 1) : 0;
+            len2 = len - split;
+
+            sdla_read(dev, addr, skb_put(skb, len2), len2);
+            if (split)
+               sdla_read(dev, buf_base, skb_put(skb, split), split);
          }
 
-         SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
-         pbuf->opp_flag = 0;
-         success = 1;
-
          /* increment the buffer we're looking at */
+         SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO);
          flp->buffer = (flp->buffer + 1) % pbufi->rse_num;
+         pbuf->opp_flag = 0;
          break;
    }
 
@@ -838,7 +876,7 @@
 
    if (!flp->initialized)
    {
-      printk(KERN_WARNING "%s: irq %d for uninitialized device.\n", dev->name, irq);
+      printk(KERN_WARNING "%s: irq %d for unintialiazed device.\n", dev->name, irq);
       return;
    }
 
@@ -872,10 +910,10 @@
       outb(flp->state, dev->base_addr + SDLA_REG_CONTROL);
    }
 
-   dev->interrupt = 0;
    /* this clears the byte, informing the Z80 we're done */
    byte = 0;
    sdla_write(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte));
+   dev->interrupt = 0;
 }
 
 static void sdla_poll(unsigned long device)
@@ -941,7 +979,6 @@
    }
 
    sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
-   sdla_stop(dev);
 
    dev->tbusy = 1;
    dev->start = 0;
@@ -973,9 +1010,6 @@
    if (!flp->configured)
       return(-EPERM);
 
-   /* off to the races! */
-   sdla_start(dev);
-
    /* time to send in the configuration */
    len = 0;
    for(i=0;i<CONFIG_DLCI_MAX;i++)
@@ -1116,6 +1150,9 @@
       memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
       flp->config.flags |= SDLA_DIRECT_RECV;
 
+      if (flp->type == SDLA_S508)
+         flp->config.flags |= SDLA_TX70_RX30;
+
       if (dev->mtu != flp->config.mtu)
       {
          /* this is required to change the MTU */
@@ -1125,7 +1162,12 @@
                flp->master[i]->mtu = flp->config.mtu;
       }
 
-      flp->config.mtu += sizeof(struct fradhdr);
+      flp->config.mtu += sizeof(struct frhdr);
+
+      /* off to the races! */
+      if (!flp->configured)
+         sdla_start(dev);
+
       flp->configured = 1;
    }
    else
@@ -1134,7 +1176,7 @@
       if (err)
          return(err);
 
-      /* no sense reading if the CPU isn't started */
+      /* no sense reading if the CPU isnt' started */
       if (dev->start)
       {
          size = sizeof(data);
@@ -1148,8 +1190,8 @@
             memset(&data.config, 0, sizeof(struct frad_conf));
 
       memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
-      data.config.flags &= ~SDLA_DIRECT_RECV;
-      data.config.mtu -= data.config.mtu > sizeof(struct fradhdr) ? sizeof(struct fradhdr) : data.config.mtu;
+      data.config.flags &= FRAD_VALID_FLAGS;
+      data.config.mtu -= data.config.mtu > sizeof(struct frhdr) ? sizeof(struct frhdr) : data.config.mtu;
       memcpy_tofs(conf, &data.config, sizeof(struct frad_conf));
    }
 
@@ -1204,13 +1246,13 @@
 
    flp = dev->priv;
 
-   memcpy(&data, &flp->config, sizeof(struct frad_conf));
-
    len = 0;
    for(i=0;i<CONFIG_DLCI_MAX;i++)
       if (flp->dlci[i])
          data.dlci[len++] = flp->dlci[i];
    len *= 2;
+
+   memcpy(&data, &flp->config, sizeof(struct frad_conf));
    len += sizeof(struct frad_conf);
 
    sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
@@ -1244,9 +1286,9 @@
 
 /* ==========================================================
 NOTE:  This is rather a useless action right now, as the
-       driver does not support protocols other than FR right
-       now.  However, Sangoma has modules for a number of
-       other protocols.
+       current driver does not support protocols other than
+       FR.  However, Sangoma has modules for a number of
+       other protocols in the works.
 ============================================================*/
       case SDLA_PROTOCOL:
          if (flp->configured)
@@ -1605,8 +1647,13 @@
 
    dev->type            = 0xFFFF;
    dev->family          = AF_UNSPEC;
-   dev->pa_alen         = sizeof(unsigned long);
+   dev->pa_alen         = 0;
+   dev->pa_addr         = 0;
+   dev->pa_dstaddr      = 0;
+   dev->pa_brdaddr      = 0;
+   dev->pa_mask         = 0;
    dev->hard_header_len = 0;
+   dev->addr_len        = 0;
    dev->mtu             = SDLA_MAX_MTU;
 
    for (i = 0; i < DEV_NUMBUFFS; i++) 
diff -u --recursive --new-file v1.3.88/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
--- v1.3.88/linux/drivers/net/tulip.c	Fri Apr 12 15:51:57 1996
+++ linux/drivers/net/tulip.c	Sun Apr 14 10:53:23 1996
@@ -21,7 +21,7 @@
 
 /* A few user-configurable values. */
 
-/* Default to using non-10baseT (i.e. AUI/10base2/100baseT port) port. */
+/* Default to using 10baseT (i.e. non-AUI/10base2/100baseT port) port. */
 #define	TULIP_10TP_PORT		0
 #define	TULIP_100TP_PORT	1
 #define	TULIP_AUI_PORT		1
@@ -561,10 +561,26 @@
 generic21040_select(struct device *dev)
 {
 	int ioaddr = dev->base_addr;
+	const char *if_port;
 
 	dev->if_port &= 3;
-	printk("%s: enabling %s port.\n",
-		   dev->name, dev->if_port ?  "AUI":"10baseT");
+	switch (dev->if_port)
+	{
+	case TULIP_10TP_PORT:
+		if_port = "10baseT";
+		break;
+	case TULIP_100TP_PORT:
+	/* TULIP_AUI_PORT is the same as TULIP_100TP_PORT. */
+		if_port = "100baseT/AUI";
+		break;
+	case TULIP_BNC_PORT:
+		if_port = "BNC";
+		break;
+	default:
+		if_port = "unknown type";
+		break;
+	}
+	printk("%s: enabling %s port.\n", dev->name, if_port);
 	/* Set the full duplex match frame. */
 	tio_write(FULL_DUPLEX_MAGIC, CSR11);
 	tio_write(TSIAC_RESET, CSR13);
diff -u --recursive --new-file v1.3.88/linux/drivers/net/wic.c linux/drivers/net/wic.c
--- v1.3.88/linux/drivers/net/wic.c	Wed Apr 10 17:02:24 1996
+++ linux/drivers/net/wic.c	Mon Apr 15 08:11:02 1996
@@ -125,10 +125,10 @@
 	enum wic_nibble_state nibble;
 	union {
 		struct {
-#if defined(LITTLE_ENDIAN)
+#if defined(__LITTLE_ENDIAN)
 			unsigned char lsb;
 			unsigned char msb;
-#elif defined(BIG_ENDIAN)
+#elif defined(__BIG_ENDIAN)
 			unsigned char msb;
 			unsigned char lsb;
 #else
diff -u --recursive --new-file v1.3.88/linux/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c
--- v1.3.88/linux/drivers/scsi/BusLogic.c	Sat Mar  9 15:41:12 1996
+++ linux/drivers/scsi/BusLogic.c	Sun Apr 14 11:21:08 1996
@@ -14,18 +14,18 @@
   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   for complete details.
 
-  The author respectfully requests that all modifications to this software be
+  The author respectfully requests that any modifications to this software be
   sent directly to him for evaluation and testing.
 
-  Special thanks to Alex T. Win of BusLogic, whose advice has been invaluable,
-  to David B. Gentzel, for writing the original Linux BusLogic driver, and to
-  Paul Gortmaker, for being such a dedicated test site.
+  Special thanks to Wayne Yen and Alex Win of BusLogic, whose advice has been
+  invaluable, to David Gentzel, for writing the original Linux BusLogic driver,
+  and to Paul Gortmaker, for being such a dedicated test site.
 
 */
 
 
-#define BusLogic_DriverVersion		"1.3.1"
-#define BusLogic_DriverDate		"31 December 1995"
+#define BusLogic_DriverVersion		"1.3.2"
+#define BusLogic_DriverDate		"13 April 1996"
 
 
 #include <linux/module.h>
@@ -87,8 +87,8 @@
 
 
 /*
-  BusLogic_Standard_IO_Addresses is the list of standard I/O Addresses at which
-  BusLogic Host Adapters may potentially be found.
+  BusLogic_StandardAddresses is the list of standard ISA I/O Addresses at
+  which BusLogic Host Adapters may potentially be found.
 */
 
 static unsigned short
@@ -120,7 +120,7 @@
 
 /*
   BusLogic_CommandFailureReason holds a string identifying the reason why a
-  call to BusLogic_Command failed.  It is only valid when BusLogic_Command
+  call to BusLogic_Command failed.  It is only non-NULL when BusLogic_Command
   returns a failure code.
 */
 
@@ -167,56 +167,6 @@
 
 
 /*
-  BusLogic_InitializeAddressProbeList initializes the list of I/O Addresses
-  to be probed for potential BusLogic SCSI Host Adapters by interrogating the
-  PCI Configuration Space on PCI machines as well as from the list of standard
-  BusLogic I/O Addresses.
-*/
-
-static void BusLogic_InitializeAddressProbeList(void)
-{
-  int DestinationIndex = 0, SourceIndex = 0;
-  /*
-    If BusLogic_Setup has been called, do not override the Kernel Command
-    Line specifications.
-  */
-  if (BusLogic_IO_AddressProbeList[0] != 0) return;
-#ifdef CONFIG_PCI
-  /*
-    Interrogate PCI Configuration Space for any BusLogic SCSI Host Adapters.
-  */
-  if (pcibios_present())
-    {
-      unsigned short Index = 0, VendorID;
-      unsigned char Bus, DeviceAndFunction;
-      unsigned int BaseAddress0;
-      while (pcibios_find_class(PCI_CLASS_STORAGE_SCSI<<8, Index++,
-				&Bus, &DeviceAndFunction) == 0)
-	if (pcibios_read_config_word(Bus, DeviceAndFunction,
-				     PCI_VENDOR_ID, &VendorID) == 0 &&
-	    VendorID == PCI_VENDOR_ID_BUSLOGIC &&
-	    pcibios_read_config_dword(Bus, DeviceAndFunction,
-				      PCI_BASE_ADDRESS_0, &BaseAddress0) == 0 &&
-	    (BaseAddress0 & PCI_BASE_ADDRESS_SPACE) ==
-	      PCI_BASE_ADDRESS_SPACE_IO)
-	  {
-	    BusLogic_IO_AddressProbeList[DestinationIndex++] =
-	      BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
-	  }
-    }
-#endif
-  /*
-    Append the list of standard BusLogic I/O Addresses.
-  */
-  while (DestinationIndex < BusLogic_IO_MaxProbeAddresses &&
-	 BusLogic_IO_StandardAddresses[SourceIndex] > 0)
-    BusLogic_IO_AddressProbeList[DestinationIndex++] =
-      BusLogic_IO_StandardAddresses[SourceIndex++];
-  BusLogic_IO_AddressProbeList[DestinationIndex] = 0;
-}
-
-
-/*
   BusLogic_RegisterHostAdapter adds Host Adapter to the list of registered
   BusLogic Host Adapters.
 */
@@ -257,6 +207,52 @@
 
 
 /*
+  BusLogic_CreateMailboxes allocates the Outgoing and Incoming Mailboxes for
+  Host Adapter.
+*/
+
+static boolean BusLogic_CreateMailboxes(BusLogic_HostAdapter_T *HostAdapter)
+{
+  HostAdapter->FirstOutgoingMailbox =
+    (BusLogic_OutgoingMailbox_T *)
+      scsi_init_malloc(HostAdapter->MailboxCount
+		       * (sizeof(BusLogic_OutgoingMailbox_T)
+			  + sizeof(BusLogic_IncomingMailbox_T)),
+		       (HostAdapter->BounceBuffersRequired
+			? GFP_ATOMIC | GFP_DMA
+			: GFP_ATOMIC));
+  if (HostAdapter->FirstOutgoingMailbox == NULL)
+    {
+      printk("scsi%d: UNABLE TO ALLOCATE MAILBOXES - DETACHING\n",
+	     HostAdapter->HostNumber);
+      return false;
+    }
+  HostAdapter->LastOutgoingMailbox =
+    HostAdapter->FirstOutgoingMailbox + HostAdapter->MailboxCount - 1;
+  HostAdapter->FirstIncomingMailbox =
+    (BusLogic_IncomingMailbox_T *) (HostAdapter->LastOutgoingMailbox + 1);
+  HostAdapter->LastIncomingMailbox =
+    HostAdapter->FirstIncomingMailbox + HostAdapter->MailboxCount - 1;
+  return true;
+}
+
+
+/*
+  BusLogic_DestroyMailboxes deallocates the Outgoing and Incoming Mailboxes
+  for Host Adapter.
+*/
+
+static void BusLogic_DestroyMailboxes(BusLogic_HostAdapter_T *HostAdapter)
+{
+  if (HostAdapter->FirstOutgoingMailbox == NULL) return;
+  scsi_init_free((char *) HostAdapter->FirstOutgoingMailbox,
+		 HostAdapter->MailboxCount
+		 * (sizeof(BusLogic_OutgoingMailbox_T)
+		    + sizeof(BusLogic_IncomingMailbox_T)));
+}
+
+
+/*
   BusLogic_CreateCCBs allocates the initial Command Control Blocks (CCBs)
   for Host Adapter.
 */
@@ -264,10 +260,13 @@
 static boolean BusLogic_CreateCCBs(BusLogic_HostAdapter_T *HostAdapter)
 {
   int i;
-  for (i = 0; i < BusLogic_InitialCCBs; i++)
+  for (i = 0; i < HostAdapter->InitialCCBs; i++)
     {
       BusLogic_CCB_T *CCB = (BusLogic_CCB_T *)
-	scsi_init_malloc(sizeof(BusLogic_CCB_T), GFP_ATOMIC | GFP_DMA);
+	scsi_init_malloc(sizeof(BusLogic_CCB_T),
+			 (HostAdapter->BounceBuffersRequired
+			  ? GFP_ATOMIC | GFP_DMA
+			  : GFP_ATOMIC));
       if (CCB == NULL)
 	{
 	  printk("scsi%d: UNABLE TO ALLOCATE CCB %d - DETACHING\n",
@@ -305,59 +304,68 @@
 
 /*
   BusLogic_AllocateCCB allocates a CCB from the Host Adapter's free list,
-  allocating more memory from the Kernel if necessary.
+  allocating more memory from the Kernel if necessary.  The Host Adapter's
+  Lock should have already been acquired by the caller.
 */
 
 static BusLogic_CCB_T *BusLogic_AllocateCCB(BusLogic_HostAdapter_T *HostAdapter)
 {
   static unsigned int SerialNumber = 0;
   BusLogic_CCB_T *CCB;
-  BusLogic_LockHostAdapter(HostAdapter);
+  int Allocated;
   CCB = HostAdapter->Free_CCBs;
   if (CCB != NULL)
     {
       CCB->SerialNumber = ++SerialNumber;
       HostAdapter->Free_CCBs = CCB->Next;
       CCB->Next = NULL;
-      BusLogic_UnlockHostAdapter(HostAdapter);
       return CCB;
     }
-  BusLogic_UnlockHostAdapter(HostAdapter);
-  CCB = (BusLogic_CCB_T *) scsi_init_malloc(sizeof(BusLogic_CCB_T),
-					    GFP_ATOMIC | GFP_DMA);
+  for (Allocated = 0; Allocated < HostAdapter->IncrementalCCBs; Allocated++)
+    {
+      CCB = (BusLogic_CCB_T *)
+	scsi_init_malloc(sizeof(BusLogic_CCB_T),
+			 (HostAdapter->BounceBuffersRequired
+			  ? GFP_ATOMIC | GFP_DMA
+			  : GFP_ATOMIC));
+      if (CCB == NULL) break;
+      memset(CCB, 0, sizeof(BusLogic_CCB_T));
+      CCB->HostAdapter = HostAdapter;
+      CCB->Status = BusLogic_CCB_Free;
+      CCB->Next = HostAdapter->Free_CCBs;
+      CCB->NextAll = HostAdapter->All_CCBs;
+      HostAdapter->Free_CCBs = CCB;
+      HostAdapter->All_CCBs = CCB;
+    }
+  CCB = HostAdapter->Free_CCBs;
   if (CCB == NULL)
     {
-      printk("scsi%d: Failed to allocate an additional CCB\n",
+      printk("scsi%d: Failed to allocate additional CCBs\n",
 	     HostAdapter->HostNumber);
       return NULL;
     }
-  printk("scsi%d: Allocated an additional CCB\n", HostAdapter->HostNumber);
-  memset(CCB, 0, sizeof(BusLogic_CCB_T));
-  CCB->HostAdapter = HostAdapter;
-  CCB->Status = BusLogic_CCB_Free;
-  BusLogic_LockHostAdapter(HostAdapter);
+  printk("scsi%d: Allocated %d additional CCBs\n",
+	 HostAdapter->HostNumber, Allocated);
   CCB->SerialNumber = ++SerialNumber;
-  CCB->NextAll = HostAdapter->All_CCBs;
-  HostAdapter->All_CCBs = CCB;
-  BusLogic_UnlockHostAdapter(HostAdapter);
+  HostAdapter->Free_CCBs = CCB->Next;
+  CCB->Next = NULL;
   return CCB;
 }
 
 
 /*
   BusLogic_DeallocateCCB deallocates a CCB, returning it to the Host Adapter's
-  free list.
+  free list.  The Host Adapter's Lock should have already been acquired by the
+  caller.
 */
 
 static void BusLogic_DeallocateCCB(BusLogic_CCB_T *CCB)
 {
   BusLogic_HostAdapter_T *HostAdapter = CCB->HostAdapter;
-  BusLogic_LockHostAdapter(HostAdapter);
   CCB->Command = NULL;
   CCB->Status = BusLogic_CCB_Free;
   CCB->Next = HostAdapter->Free_CCBs;
   HostAdapter->Free_CCBs = CCB;
-  BusLogic_UnlockHostAdapter(HostAdapter);
 }
 
 
@@ -374,9 +382,9 @@
   This function is only called during board detection and initialization, so
   performance and latency are not critical, and exclusive access to the Host
   Adapter hardware is assumed.  Once the board and driver are initialized, the
-  only Host Adapter command that is issued is the single byte Start Mailbox
-  Scan command, which does not require waiting for the Host Adapter Ready bit
-  to be set in the Status Register.
+  only Host Adapter command that is issued is the single byte Execute Mailbox
+  Command operation code , which does not require waiting for the Host Adapter
+  Ready bit to be set in the Status Register.
 */
 
 static int BusLogic_Command(BusLogic_HostAdapter_T *HostAdapter,
@@ -463,6 +471,7 @@
     {
     case BusLogic_InquireInstalledDevicesID0to7:
     case BusLogic_InquireInstalledDevicesID8to15:
+    case BusLogic_InquireDevices:
       /* Approximately 60 seconds. */
       TimeoutCounter = loops_per_sec << 2;
       break;
@@ -486,6 +495,8 @@
 	if (++ReplyBytes <= ReplyLength)
 	  *ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter);
 	else BusLogic_ReadDataInRegister(HostAdapter);
+      if (OperationCode == BusLogic_FetchHostAdapterLocalRAM &&
+	  (StatusRegister & BusLogic_HostAdapterReady)) break;
     }
   BusLogic_CommandFailureReason = "Timeout waiting for Command Complete";
   if (TimeoutCounter < 0) return -2;
@@ -551,6 +562,121 @@
 
 
 /*
+  BusLogic_InitializeAddressProbeList initializes the list of I/O Addresses
+  to be probed for potential BusLogic SCSI Host Adapters by interrogating the
+  PCI Configuration Space on PCI machines as well as from the list of standard
+  BusLogic I/O Addresses.
+*/
+
+static void BusLogic_InitializeAddressProbeList(void)
+{
+  int DestinationIndex = 0, SourceIndex = 0;
+  /*
+    If BusLogic_Setup has provided an I/O Address probe list, do not override
+    the Kernel Command Line specifications.
+  */
+  if (BusLogic_IO_AddressProbeList[0] != 0) return;
+#ifdef CONFIG_PCI
+  /*
+    Interrogate PCI Configuration Space for any BusLogic SCSI Host Adapters.
+  */
+  if (pcibios_present())
+    {
+      unsigned short BusDeviceFunction[BusLogic_IO_MaxProbeAddresses];
+      unsigned short Index = 0, VendorID, DeviceID;
+      boolean NonIncreasingScanningOrder = false;
+      unsigned char Bus, DeviceFunction;
+      unsigned int BaseAddress0;
+      while (pcibios_find_class(PCI_CLASS_STORAGE_SCSI<<8, Index++,
+				&Bus, &DeviceFunction) == 0)
+	if (pcibios_read_config_word(Bus, DeviceFunction,
+				     PCI_VENDOR_ID, &VendorID) == 0 &&
+	    VendorID == PCI_VENDOR_ID_BUSLOGIC &&
+	    pcibios_read_config_word(Bus, DeviceFunction,
+				     PCI_DEVICE_ID, &DeviceID) == 0 &&
+	    (DeviceID == PCI_DEVICE_ID_BUSLOGIC_946C ||
+	     DeviceID == PCI_DEVICE_ID_BUSLOGIC_946C_2) &&
+	    pcibios_read_config_dword(Bus, DeviceFunction,
+				      PCI_BASE_ADDRESS_0, &BaseAddress0) == 0 &&
+	    (BaseAddress0 & PCI_BASE_ADDRESS_SPACE) ==
+	      PCI_BASE_ADDRESS_SPACE_IO)
+	  {
+	    BusLogic_IO_AddressProbeList[DestinationIndex] =
+	      BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
+	    BusDeviceFunction[DestinationIndex] = (Bus << 8) | DeviceFunction;
+	    if (DestinationIndex > 0 &&
+		BusDeviceFunction[DestinationIndex] <
+		  BusDeviceFunction[DestinationIndex-1])
+	      NonIncreasingScanningOrder = true;
+	    DestinationIndex++;
+	  }
+      /*
+	If there are multiple BusLogic PCI SCSI Host Adapters present and if
+	they are enumerated by the PCI BIOS in an order other than by strictly
+	increasing Bus Number and Device Number, then interrogate the setting
+	of the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option.
+	If it is ON, sort the PCI Host Adapter I/O Addresses by increasing Bus
+	Number and Device Number so that the Host Adapters are recognized in
+	the same order by the Linux kernel as by the Host Adapter's BIOS.
+      */
+      if (DestinationIndex > 1 && NonIncreasingScanningOrder)
+	{
+	  BusLogic_FetchHostAdapterLocalRAMRequest_T
+	    FetchHostAdapterLocalRAMRequest;
+	  BusLogic_AutoSCSIByte45_T AutoSCSIByte45;
+	  BusLogic_HostAdapter_T HostAdapterPrototype;
+	  BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype;
+	  HostAdapter->IO_Address = BusLogic_IO_AddressProbeList[0];
+	  FetchHostAdapterLocalRAMRequest.ByteOffset =
+	    BusLogic_AutoSCSI_BaseOffset + 45;
+	  FetchHostAdapterLocalRAMRequest.ByteCount = sizeof(AutoSCSIByte45);
+	  AutoSCSIByte45.ForceBusDeviceScanningOrder = false;
+	  BusLogic_Command(HostAdapter,
+			   BusLogic_FetchHostAdapterLocalRAM,
+			   &FetchHostAdapterLocalRAMRequest,
+			   sizeof(FetchHostAdapterLocalRAMRequest),
+			   &AutoSCSIByte45, sizeof(AutoSCSIByte45));
+	  if (AutoSCSIByte45.ForceBusDeviceScanningOrder)
+	    {
+	      /*
+		Sort the I/O Addresses such that the corrseponding PCI devices
+		are in ascending order by Bus Number and Device Number.
+	      */
+	      int LastInterchange = DestinationIndex-1, Bound, j;
+	      while (LastInterchange > 0)
+		{
+		  Bound = LastInterchange;
+		  LastInterchange = 0;
+		  for (j = 0; j < Bound; j++)
+		    if (BusDeviceFunction[j] > BusDeviceFunction[j+1])
+		      {
+			unsigned short Temp;
+			Temp = BusDeviceFunction[j];
+			BusDeviceFunction[j] = BusDeviceFunction[j+1];
+			BusDeviceFunction[j+1] = Temp;
+			Temp = BusLogic_IO_AddressProbeList[j];
+			BusLogic_IO_AddressProbeList[j] =
+			  BusLogic_IO_AddressProbeList[j+1];
+			BusLogic_IO_AddressProbeList[j+1] = Temp;
+			LastInterchange = j;
+		      }
+		}
+	    }
+	}
+    }
+#endif
+  /*
+    Append the list of standard BusLogic ISA I/O Addresses.
+  */
+  while (DestinationIndex < BusLogic_IO_MaxProbeAddresses &&
+	 BusLogic_IO_StandardAddresses[SourceIndex] > 0)
+    BusLogic_IO_AddressProbeList[DestinationIndex++] =
+      BusLogic_IO_StandardAddresses[SourceIndex++];
+  BusLogic_IO_AddressProbeList[DestinationIndex] = 0;
+}
+
+
+/*
   BusLogic_Failure prints a standardized error message, and then returns false.
 */
 
@@ -749,6 +875,9 @@
   BusLogic_BoardModelNumber_T BoardModelNumber;
   BusLogic_FirmwareVersion3rdDigit_T FirmwareVersion3rdDigit;
   BusLogic_FirmwareVersionLetter_T FirmwareVersionLetter;
+  BusLogic_GenericIOPortInformation_T GenericIOPortInformation;
+  BusLogic_FetchHostAdapterLocalRAMRequest_T FetchHostAdapterLocalRAMRequest;
+  BusLogic_AutoSCSIByte15_T AutoSCSIByte15;
   BusLogic_RequestedReplyLength_T RequestedReplyLength;
   unsigned char GeometryRegister, *TargetPointer, Character;
   unsigned short AllTargetsMask, DisconnectPermitted;
@@ -825,6 +954,8 @@
     BusLogic Host Adapters can be identified by their model number and
     the major version number of their firmware as follows:
 
+    5.xx	BusLogic "W" Series Host Adapters:
+		  BT-948/958/958D
     4.xx	BusLogic "C" Series Host Adapters:
 		  BT-946C/956C/956CD/747C/757C/757CD/445C/545C/540CF
     3.xx	BusLogic "S" Series Host Adapters:
@@ -835,6 +966,54 @@
     0.xx	AMI FastDisk VLB/EISA BusLogic Clone Host Adapter
   */
   /*
+    Issue the Inquire Generic I/O Port Information command to read the
+    termination information from "W" Series Host Adapters.
+  */
+  if (BoardID.FirmwareVersion1stDigit == '5')
+    {
+      if (BusLogic_Command(HostAdapter,
+			   BusLogic_InquireGenericIOPortInformation,
+			   NULL, 0, &GenericIOPortInformation,
+			   sizeof(GenericIOPortInformation))
+	  != sizeof(GenericIOPortInformation))
+	return BusLogic_Failure(HostAdapter,
+				"INQUIRE GENERIC I/O PORT INFORMATION");
+      /*
+	Save the Termination Information in the Host Adapter structure.
+      */
+      if (GenericIOPortInformation.Valid)
+	{
+	  HostAdapter->TerminationInfoValid = true;
+	  HostAdapter->LowByteTerminated =
+	    GenericIOPortInformation.LowByteTerminated;
+	  HostAdapter->HighByteTerminated =
+	    GenericIOPortInformation.HighByteTerminated;
+	}
+    }
+  /*
+    Issue the Fetch Host Adapter Local RAM command to read the termination
+    information from the AutoSCSI area of "C" Series Host Adapters.
+  */
+  if (BoardID.FirmwareVersion1stDigit == '4')
+    {
+      FetchHostAdapterLocalRAMRequest.ByteOffset =
+	BusLogic_AutoSCSI_BaseOffset + 15;
+      FetchHostAdapterLocalRAMRequest.ByteCount = sizeof(AutoSCSIByte15);
+      if (BusLogic_Command(HostAdapter,
+			   BusLogic_FetchHostAdapterLocalRAM,
+			   &FetchHostAdapterLocalRAMRequest,
+			   sizeof(FetchHostAdapterLocalRAMRequest),
+			   &AutoSCSIByte15, sizeof(AutoSCSIByte15))
+	  != sizeof(AutoSCSIByte15))
+	return BusLogic_Failure(HostAdapter, "FETCH HOST ADAPTER LOCAL RAM");
+      /*
+	Save the Termination Information in the Host Adapter structure.
+      */
+      HostAdapter->TerminationInfoValid = true;
+      HostAdapter->LowByteTerminated = AutoSCSIByte15.LowByteTerminated;
+      HostAdapter->HighByteTerminated = AutoSCSIByte15.HighByteTerminated;
+    }
+  /*
     Save the Model Name and Board Name in the Host Adapter structure.
   */
   TargetPointer = HostAdapter->ModelName;
@@ -902,31 +1081,28 @@
     Determine the Bus Type and save it in the Host Adapter structure,
     overriding the DMA Channel if it is inappropriate for the bus type.
   */
-  if (ExtendedSetupInformation.BusType == 'A')
-    HostAdapter->BusType = BusLogic_ISA_Bus;
-  else
-    switch (HostAdapter->ModelName[3])
-      {
-      case '4':
-	HostAdapter->BusType = BusLogic_VESA_Bus;
-	HostAdapter->DMA_Channel = 0;
-	break;
-      case '5':
-	HostAdapter->BusType = BusLogic_ISA_Bus;
-	break;
-      case '6':
-	HostAdapter->BusType = BusLogic_MCA_Bus;
-	HostAdapter->DMA_Channel = 0;
-	break;
-      case '7':
-	HostAdapter->BusType = BusLogic_EISA_Bus;
-	HostAdapter->DMA_Channel = 0;
-	break;
-      case '9':
-	HostAdapter->BusType = BusLogic_PCI_Bus;
-	HostAdapter->DMA_Channel = 0;
-	break;
-      }
+  switch (HostAdapter->ModelName[3])
+    {
+    case '4':
+      HostAdapter->BusType = BusLogic_VESA_Bus;
+      HostAdapter->DMA_Channel = 0;
+      break;
+    case '5':
+      HostAdapter->BusType = BusLogic_ISA_Bus;
+      break;
+    case '6':
+      HostAdapter->BusType = BusLogic_MCA_Bus;
+      HostAdapter->DMA_Channel = 0;
+      break;
+    case '7':
+      HostAdapter->BusType = BusLogic_EISA_Bus;
+      HostAdapter->DMA_Channel = 0;
+      break;
+    case '9':
+      HostAdapter->BusType = BusLogic_PCI_Bus;
+      HostAdapter->DMA_Channel = 0;
+      break;
+    }
   /*
     Determine whether Extended Translation is enabled and save it in
     the Host Adapter structure.
@@ -936,8 +1112,8 @@
     HostAdapter->ExtendedTranslation = true;
   /*
     Save the Disconnect/Reconnect Permitted flag bits in the Host Adapter
-    structure.  The Disconnect Permitted information is only valid on "C"
-    Series boards, but Disconnect/Reconnect is always permitted on "S" and
+    structure.  The Disconnect Permitted information is only valid on "W" and
+    "C" Series boards, but Disconnect/Reconnect is always permitted on "S" and
     "A" Series boards.
   */
   if (HostAdapter->FirmwareVersion[0] >= '4')
@@ -946,8 +1122,9 @@
       | SetupInformation.DisconnectPermittedID0to7;
   else HostAdapter->DisconnectPermitted = 0xFF;
   /*
-    Save the Scatter Gather Limits, Level Sensitive Interrupts flag,
-    Wide SCSI flag, and Differential SCSI flag in the Host Adapter structure.
+    Save the Scatter Gather Limits, Level Sensitive Interrupts flag, Wide
+    SCSI flag, Differential SCSI flag, Automatic Configuration flag, and
+    Ultra SCSI flag in the Host Adapter structure.
   */
   HostAdapter->HostAdapterScatterGatherLimit =
     ExtendedSetupInformation.ScatterGatherLimit;
@@ -957,20 +1134,12 @@
     HostAdapter->DriverScatterGatherLimit = BusLogic_ScatterGatherLimit;
   if (ExtendedSetupInformation.Misc.LevelSensitiveInterrupts)
     HostAdapter->LevelSensitiveInterrupts = true;
-  if (ExtendedSetupInformation.HostWideSCSI)
-    {
-      HostAdapter->HostWideSCSI = true;
-      HostAdapter->MaxTargetIDs = 16;
-      HostAdapter->MaxLogicalUnits = 64;
-    }
-  else
-    {
-      HostAdapter->HostWideSCSI = false;
-      HostAdapter->MaxTargetIDs = 8;
-      HostAdapter->MaxLogicalUnits = 8;
-    }
+  HostAdapter->HostWideSCSI = ExtendedSetupInformation.HostWideSCSI;
   HostAdapter->HostDifferentialSCSI =
     ExtendedSetupInformation.HostDifferentialSCSI;
+  HostAdapter->HostAutomaticConfiguration =
+    ExtendedSetupInformation.HostAutomaticConfiguration;
+  HostAdapter->HostUltraSCSI = ExtendedSetupInformation.HostUltraSCSI;
   /*
     Determine the Host Adapter BIOS Address if the BIOS is enabled and
     save it in the Host Adapter structure.  The BIOS is disabled if the
@@ -978,29 +1147,98 @@
   */
   HostAdapter->BIOS_Address = ExtendedSetupInformation.BIOS_Address << 12;
   /*
-    BusLogic BT-445S Host Adapters prior to board revision D have a hardware
+    ISA Host Adapters require Bounce Buffers if there is more than 16MB memory.
+  */
+  if (HostAdapter->BusType == BusLogic_ISA_Bus && high_memory > MAX_DMA_ADDRESS)
+    HostAdapter->BounceBuffersRequired = true;
+  /*
+    BusLogic BT-445S Host Adapters prior to board revision E have a hardware
     bug whereby when the BIOS is enabled, transfers to/from the same address
     range the BIOS occupies modulo 16MB are handled incorrectly.  Only properly
     functioning BT-445S boards have firmware version 3.37, so we require that
-    ISA bounce buffers be used for the buggy BT-445S models as well as for all
-    ISA models.
+    ISA Bounce Buffers be used for the buggy BT-445S models if there is more
+    than 16MB memory.
   */
-  if (HostAdapter->BusType == BusLogic_ISA_Bus ||
-      (HostAdapter->BIOS_Address > 0 &&
-       strcmp(HostAdapter->ModelName, "BT-445S") == 0 &&
-       strcmp(HostAdapter->FirmwareVersion, "3.37") < 0))
+  if (HostAdapter->BIOS_Address > 0 &&
+      strcmp(HostAdapter->ModelName, "BT-445S") == 0 &&
+      strcmp(HostAdapter->FirmwareVersion, "3.37") < 0 &&
+      high_memory > MAX_DMA_ADDRESS)
     HostAdapter->BounceBuffersRequired = true;
   /*
-    Select an appropriate value for Concurrency (Commands per Logical Unit)
-    either from a Command Line Entry, or based on whether this Host Adapter
-    requires that ISA bounce buffers be used.
+    Determine the maximum number of Target IDs and Logical Units supported by
+    this driver for Wide and Narrow Host Adapters.
+  */
+  if (HostAdapter->HostWideSCSI)
+    {
+      HostAdapter->MaxTargetDevices = 16;
+      HostAdapter->MaxLogicalUnits = 64;
+    }
+  else
+    {
+      HostAdapter->MaxTargetDevices = 8;
+      HostAdapter->MaxLogicalUnits = 8;
+    }
+  /*
+    Select appropriate values for the Mailbox Count, Initial CCBs, and
+    Incremental CCBs variables based on whether or not Strict Round Robin Mode
+    is supported.  If Strict Round Robin Mode is supported, then there is no
+    performance degradation in using the maximum possible number of Outgoing
+    and Incoming Mailboxes and allowing the Tagged and Untagged Queue Depths to
+    determine the actual utilization.  If Strict Round Robin Mode is not
+    supported, then the Host Adapter must scan all the Outgoing Mailboxes
+    whenever an Outgoing Mailbox entry is made, which can cause a substantial
+    performance penalty.  The Host Adapters actually have room to store the
+    following number of CCBs internally; that is, they can internally queue and
+    manage this many active commands on the SCSI bus simultaneously.
+    Performance measurements demonstrate that the Mailbox Count should be set
+    to the maximum possible, rather than the internal CCB capacity, as it is
+    more efficient to have the queued commands waiting in Outgoing Mailboxes if
+    necessary than to block the process in the higher levels of the SCSI
+    Subsystem.
+
+	192	  BT-948/958/958D
+	100	  BT-946C/956C/956CD/747C/757C/757CD/445C
+	 50	  BT-545C/540CF
+	 30	  BT-747S/747D/757S/757D/445S/545S/542D/542B/742A
+  */
+  if (strcmp(HostAdapter->FirmwareVersion, "3.31") >= 0)
+    {
+      HostAdapter->StrictRoundRobinModeSupported = true;
+      HostAdapter->MailboxCount = 255;
+      HostAdapter->InitialCCBs = 64;
+      HostAdapter->IncrementalCCBs = 32;
+    }
+  else
+    {
+      HostAdapter->StrictRoundRobinModeSupported = false;
+      HostAdapter->MailboxCount = 32;
+      HostAdapter->InitialCCBs = 32;
+      HostAdapter->IncrementalCCBs = 4;
+    }
+  if (HostAdapter->FirmwareVersion[0] == '5')
+    HostAdapter->TotalQueueDepth = 192;
+  else if (HostAdapter->FirmwareVersion[0] == '4')
+    HostAdapter->TotalQueueDepth =
+      (HostAdapter->BusType != BusLogic_ISA_Bus ? 100 : 50);
+  else HostAdapter->TotalQueueDepth = 30;
+  /*
+    Select an appropriate value for the Tagged Queue Depth either from a
+    Command Line Entry, or based on whether this Host Adapter requires that
+    ISA Bounce Buffers be used.  The Tagged Queue Depth is left at 0 for
+    automatic determination in BusLogic_SelectQueueDepths.  Initialize the
+    Untagged Queue Depth.
   */
   if (HostAdapter->CommandLineEntry != NULL &&
-      HostAdapter->CommandLineEntry->Concurrency > 0)
-    HostAdapter->Concurrency = HostAdapter->CommandLineEntry->Concurrency;
+      HostAdapter->CommandLineEntry->TaggedQueueDepth > 0)
+    HostAdapter->TaggedQueueDepth =
+      HostAdapter->CommandLineEntry->TaggedQueueDepth;
   else if (HostAdapter->BounceBuffersRequired)
-    HostAdapter->Concurrency = BusLogic_Concurrency_BB;
-  else HostAdapter->Concurrency = BusLogic_Concurrency;
+    HostAdapter->TaggedQueueDepth = BusLogic_TaggedQueueDepth_BB;
+  else HostAdapter->TaggedQueueDepth = 0;
+  HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth;
+  if (HostAdapter->UntaggedQueueDepth > HostAdapter->TaggedQueueDepth &&
+      HostAdapter->TaggedQueueDepth > 0)
+    HostAdapter->UntaggedQueueDepth = HostAdapter->TaggedQueueDepth;
   /*
     Select an appropriate value for Bus Settle Time either from a Command
     Line Entry, or from BusLogic_DefaultBusSettleTime.
@@ -1015,25 +1253,25 @@
   if (HostAdapter->CommandLineEntry != NULL)
     HostAdapter->LocalOptions = HostAdapter->CommandLineEntry->LocalOptions;
   /*
-    Select appropriate values for the Error Recovery Option array either from
-    a Command Line Entry, or using BusLogic_ErrorRecoveryDefault.
+    Select appropriate values for the Error Recovery Strategy array either from
+    a Command Line Entry, or using BusLogic_ErrorRecovery_Default.
   */
   if (HostAdapter->CommandLineEntry != NULL)
-    memcpy(HostAdapter->ErrorRecoveryOption,
-	   HostAdapter->CommandLineEntry->ErrorRecoveryOption,
-	   sizeof(HostAdapter->ErrorRecoveryOption));
-  else memset(HostAdapter->ErrorRecoveryOption,
-	      BusLogic_ErrorRecoveryDefault,
-	      sizeof(HostAdapter->ErrorRecoveryOption));
-  /*
-    Tagged Queuing support is available and operates properly only on "C"
-    Series boards with firmware version 4.22 and above and on "S" Series
-    boards with firmware version 3.35 and above.  Tagged Queuing is disabled
-    by default when the Concurrency value is 1 since queuing multiple commands
-    is not possible.
+    memcpy(HostAdapter->ErrorRecoveryStrategy,
+	   HostAdapter->CommandLineEntry->ErrorRecoveryStrategy,
+	   sizeof(HostAdapter->ErrorRecoveryStrategy));
+  else memset(HostAdapter->ErrorRecoveryStrategy,
+	      BusLogic_ErrorRecovery_Default,
+	      sizeof(HostAdapter->ErrorRecoveryStrategy));
+  /*
+    Tagged Queuing support is available and operates properly on all "W" Series
+    boards, on "C" Series boards with firmware version 4.22 and above, and on
+    "S" Series boards with firmware version 3.35 and above.  Tagged Queuing is
+    disabled by default when the Tagged Queue Depth is 1 since queuing multiple
+    commands is not possible.
   */
   TaggedQueuingPermittedDefault = 0;
-  if (HostAdapter->Concurrency > 1)
+  if (HostAdapter->TaggedQueueDepth != 1)
     switch (HostAdapter->FirmwareVersion[0])
       {
       case '5':
@@ -1055,8 +1293,8 @@
   */
   TaggedQueuingPermittedDefault &= HostAdapter->DisconnectPermitted;
   /*
-    Combine the default Tagged Queuing Permitted Default bits with any
-    Command Line Entry Tagged Queuing specification.
+    Combine the default Tagged Queuing Permitted bits with any Command
+    Line Entry Tagged Queuing specification.
   */
   if (HostAdapter->CommandLineEntry != NULL)
     HostAdapter->TaggedQueuingPermitted =
@@ -1068,11 +1306,12 @@
   /*
     Announce the Host Adapter Configuration.
   */
-  printk("scsi%d: Configuring BusLogic Model %s %s%s%s SCSI Host Adapter\n",
+  printk("scsi%d: Configuring BusLogic Model %s %s%s%s%s SCSI Host Adapter\n",
 	 HostAdapter->HostNumber, HostAdapter->ModelName,
 	 BusLogic_BusNames[HostAdapter->BusType],
 	 (HostAdapter->HostWideSCSI ? " Wide" : ""),
-	 (HostAdapter->HostDifferentialSCSI ? " Differential" : ""));
+	 (HostAdapter->HostDifferentialSCSI ? " Differential" : ""),
+	 (HostAdapter->HostUltraSCSI ? " Ultra" : ""));
   printk("scsi%d:   Firmware Version: %s, I/O Address: 0x%X, "
 	 "IRQ Channel: %d/%s\n",
 	 HostAdapter->HostNumber, HostAdapter->FirmwareVersion,
@@ -1086,15 +1325,16 @@
     printk("BIOS Address: 0x%lX, ", HostAdapter->BIOS_Address);
   else printk("BIOS Address: None, ");
   printk("Host Adapter SCSI ID: %d\n", HostAdapter->SCSI_ID);
-  printk("scsi%d:   Scatter/Gather Limit: %d segments, "
-	 "Synchronous Initiation: %s\n", HostAdapter->HostNumber,
+  printk("scsi%d:   Scatter/Gather Limit: %d of %d segments, "
+	 "Parity Checking: %s\n", HostAdapter->HostNumber,
+	 HostAdapter->DriverScatterGatherLimit,
 	 HostAdapter->HostAdapterScatterGatherLimit,
-	 (HostAdapter->SynchronousInitiation ? "Enabled" : "Disabled"));
-  printk("scsi%d:   SCSI Parity Checking: %s, "
+	 (HostAdapter->ParityChecking ? "Enabled" : "Disabled"));
+  printk("scsi%d:   Synchronous Initiation: %s, "
 	 "Extended Disk Translation: %s\n", HostAdapter->HostNumber,
-	 (HostAdapter->ParityChecking ? "Enabled" : "Disabled"),
+	 (HostAdapter->SynchronousInitiation ? "Enabled" : "Disabled"),
 	 (HostAdapter->ExtendedTranslation ? "Enabled" : "Disabled"));
-  AllTargetsMask = (1 << HostAdapter->MaxTargetIDs) - 1;
+  AllTargetsMask = (1 << HostAdapter->MaxTargetDevices) - 1;
   DisconnectPermitted = HostAdapter->DisconnectPermitted & AllTargetsMask;
   printk("scsi%d:   Disconnect/Reconnect: ", HostAdapter->HostNumber);
   if (DisconnectPermitted == 0)
@@ -1102,7 +1342,7 @@
   else if (DisconnectPermitted == AllTargetsMask)
     printk("Enabled");
   else
-    for (TargetID = 0; TargetID < HostAdapter->MaxTargetIDs; TargetID++)
+    for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
       printk("%c", (DisconnectPermitted & (1 << TargetID)) ? 'Y' : 'N');
   printk(", Tagged Queuing: ");
   TaggedQueuingPermitted =
@@ -1112,30 +1352,43 @@
   else if (TaggedQueuingPermitted == AllTargetsMask)
     printk("Enabled");
   else
-    for (TargetID = 0; TargetID < HostAdapter->MaxTargetIDs; TargetID++)
+    for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
       printk("%c", (TaggedQueuingPermitted & (1 << TargetID)) ? 'Y' : 'N');
   printk("\n");
+  printk("scsi%d:   Total Queue Depth: %d, Mailboxes: %d, Initial CCBs: %d\n",
+	 HostAdapter->HostNumber, HostAdapter->TotalQueueDepth,
+	 HostAdapter->MailboxCount, HostAdapter->InitialCCBs);
+  printk("scsi%d:   Tagged Queue Depth: ", HostAdapter->HostNumber);
+  if (HostAdapter->TaggedQueueDepth > 0)
+    printk("%d", HostAdapter->TaggedQueueDepth);
+  else printk("Automatic");
+  printk(", Untagged Queue Depth: %d\n", HostAdapter->UntaggedQueueDepth);
+  if (HostAdapter->TerminationInfoValid)
+    if (HostAdapter->HostWideSCSI)
+      printk("scsi%d:   Host Adapter SCSI Bus Termination (Low/High): %s/%s\n",
+	     HostAdapter->HostNumber,
+	     (HostAdapter->LowByteTerminated ? "Enabled" : "Disabled"),
+	     (HostAdapter->HighByteTerminated ? "Enabled" : "Disabled"));
+    else printk("scsi%d:   Host Adapter SCSI Bus Termination: %s\n",
+		HostAdapter->HostNumber,
+		(HostAdapter->LowByteTerminated ? "Enabled" : "Disabled"));
   CommonErrorRecovery = true;
-  for (TargetID = 1; TargetID < HostAdapter->MaxTargetIDs; TargetID++)
-    if (HostAdapter->ErrorRecoveryOption[TargetID] !=
-	HostAdapter->ErrorRecoveryOption[0])
+  for (TargetID = 1; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+    if (HostAdapter->ErrorRecoveryStrategy[TargetID] !=
+	HostAdapter->ErrorRecoveryStrategy[0])
       {
 	CommonErrorRecovery = false;
 	break;
       }
-  printk("scsi%d:   Error Recovery: ", HostAdapter->HostNumber);
+  printk("scsi%d:   Error Recovery Strategy: ", HostAdapter->HostNumber);
   if (CommonErrorRecovery)
-    printk("%s", BusLogic_ErrorRecoveryOptions[
-		   HostAdapter->ErrorRecoveryOption[0]]);
+    printk("%s", BusLogic_ErrorRecoveryStrategyNames[
+		   HostAdapter->ErrorRecoveryStrategy[0]]);
   else
-    for (TargetID = 0; TargetID < HostAdapter->MaxTargetIDs; TargetID++)
-      printk("%s", BusLogic_ErrorRecoveryOptions2[
-		     HostAdapter->ErrorRecoveryOption[TargetID]]);
-  printk(", Mailboxes: %d, Initial CCBs: %d\n",
-	 BusLogic_MailboxCount, BusLogic_InitialCCBs);
-  printk("scsi%d:   Driver Scatter/Gather Limit: %d segments, "
-	 "Concurrency: %d\n", HostAdapter->HostNumber,
-	 HostAdapter->DriverScatterGatherLimit, HostAdapter->Concurrency);
+    for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+      printk("%s", BusLogic_ErrorRecoveryStrategyLetters[
+		     HostAdapter->ErrorRecoveryStrategy[TargetID]]);
+  printk("\n");
   /*
     Indicate reading the Host Adapter Configuration completed successfully.
   */
@@ -1144,25 +1397,27 @@
 
 
 /*
-  BusLogic_AcquireResources acquires the system resources necessary to use Host
-  Adapter, and initializes the fields in the SCSI Host structure.  The base,
-  io_port, n_io_ports, irq, and dma_channel fields in the SCSI Host structure
-  are intentionally left uninitialized, as this driver handles acquisition and
-  release of these resources explicitly, as well as ensuring exclusive access
-  to the Host Adapter hardware and data structures through explicit locking.
+  BusLogic_AcquireResources acquires the system resources necessary to use
+  Host Adapter.
 */
 
-static boolean BusLogic_AcquireResources(BusLogic_HostAdapter_T *HostAdapter,
-					 SCSI_Host_T *Host)
+static boolean BusLogic_AcquireResources(BusLogic_HostAdapter_T *HostAdapter)
 {
+  if (HostAdapter->IRQ_Channel == 0)
+    {
+      printk("scsi%d: NO INTERRUPT CHANNEL ASSIGNED - DETACHING\n",
+	     HostAdapter->HostNumber);
+      return false;
+    }
   /*
     Acquire exclusive or shared access to the IRQ Channel.  A usage count is
-    maintained so that PCI, EISA, or MCA shared Interrupts can be supported.
+    maintained so that PCI, EISA, or MCA shared interrupts can be supported.
   */
   if (BusLogic_IRQ_UsageCount[HostAdapter->IRQ_Channel - 9]++ == 0)
     {
       if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler,
-		      SA_INTERRUPT, HostAdapter->InterruptLabel, NULL) < 0)
+		      SA_INTERRUPT | SA_SHIRQ,
+		      HostAdapter->InterruptLabel, NULL) < 0)
 	{
 	  BusLogic_IRQ_UsageCount[HostAdapter->IRQ_Channel - 9]--;
 	  printk("scsi%d: UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n",
@@ -1207,17 +1462,6 @@
       HostAdapter->DMA_ChannelAcquired = true;
     }
   /*
-    Initialize necessary fields in the SCSI Host structure.
-  */
-  Host->max_id = HostAdapter->MaxTargetIDs;
-  Host->max_lun = HostAdapter->MaxLogicalUnits;
-  Host->max_channel = 0;
-  Host->this_id = HostAdapter->SCSI_ID;
-  Host->can_queue = BusLogic_MailboxCount;
-  Host->cmd_per_lun = HostAdapter->Concurrency;
-  Host->sg_tablesize = HostAdapter->DriverScatterGatherLimit;
-  Host->unchecked_isa_dma = HostAdapter->BounceBuffersRequired;
-  /*
     Indicate the System Resource Acquisition completed successfully,
   */
   return true;
@@ -1306,51 +1550,51 @@
   BusLogic_RoundRobinModeRequest_T RoundRobinModeRequest;
   BusLogic_WideModeCCBRequest_T WideModeCCBRequest;
   BusLogic_ModifyIOAddressRequest_T ModifyIOAddressRequest;
+  int TargetID;
   /*
-    Initialize the Command Successful Flag, Read/Write Operation Count,
-    and Queued Operation Count for each Target.
-  */
+    Initialize the Bus Device Reset Pending CCB, Tagged Queuing Active,
+    Command Successful Flag, Active Command Count, and Total Command Count
+    for each Target Device.
+  */
+  for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+    HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL;
+  memset(HostAdapter->TaggedQueuingActive, false,
+	 sizeof(HostAdapter->TaggedQueuingActive));
   memset(HostAdapter->CommandSuccessfulFlag, false,
 	 sizeof(HostAdapter->CommandSuccessfulFlag));
-  memset(HostAdapter->ReadWriteOperationCount, 0,
-	 sizeof(HostAdapter->ReadWriteOperationCount));
-  memset(HostAdapter->QueuedOperationCount, 0,
-	 sizeof(HostAdapter->QueuedOperationCount));
+  memset(HostAdapter->ActiveCommandCount, 0,
+	 sizeof(HostAdapter->ActiveCommandCount));
+  memset(HostAdapter->TotalCommandCount, 0,
+	 sizeof(HostAdapter->TotalCommandCount));
   /*
     Initialize the Outgoing and Incoming Mailbox structures.
   */
-  memset(HostAdapter->OutgoingMailboxes, 0,
-	 sizeof(HostAdapter->OutgoingMailboxes));
-  memset(HostAdapter->IncomingMailboxes, 0,
-	 sizeof(HostAdapter->IncomingMailboxes));
+  memset(HostAdapter->FirstOutgoingMailbox, 0,
+	 HostAdapter->MailboxCount * sizeof(BusLogic_OutgoingMailbox_T));
+  memset(HostAdapter->FirstIncomingMailbox, 0,
+	 HostAdapter->MailboxCount * sizeof(BusLogic_IncomingMailbox_T));
   /*
-    Initialize the pointers to the First, Last, and Next Mailboxes.
+    Initialize the pointers to the Next Mailboxes.
   */
-  HostAdapter->FirstOutgoingMailbox = &HostAdapter->OutgoingMailboxes[0];
-  HostAdapter->LastOutgoingMailbox =
-    &HostAdapter->OutgoingMailboxes[BusLogic_MailboxCount-1];
   HostAdapter->NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox;
-  HostAdapter->FirstIncomingMailbox = &HostAdapter->IncomingMailboxes[0];
-  HostAdapter->LastIncomingMailbox =
-    &HostAdapter->IncomingMailboxes[BusLogic_MailboxCount-1];
   HostAdapter->NextIncomingMailbox = HostAdapter->FirstIncomingMailbox;
   /*
     Initialize the Host Adapter's Pointer to the Outgoing/Incoming Mailboxes.
   */
-  ExtendedMailboxRequest.MailboxCount = BusLogic_MailboxCount;
-  ExtendedMailboxRequest.BaseMailboxAddress = HostAdapter->OutgoingMailboxes;
+  ExtendedMailboxRequest.MailboxCount = HostAdapter->MailboxCount;
+  ExtendedMailboxRequest.BaseMailboxAddress = HostAdapter->FirstOutgoingMailbox;
   if (BusLogic_Command(HostAdapter, BusLogic_InitializeExtendedMailbox,
 		       &ExtendedMailboxRequest,
 		       sizeof(ExtendedMailboxRequest), NULL, 0) < 0)
     return BusLogic_Failure(HostAdapter, "MAILBOX INITIALIZATION");
   /*
-    Enable Strict Round Robin Mode if supported by the Host Adapter.  In Strict
-    Round Robin Mode, the Host Adapter only looks at the next Outgoing Mailbox
-    for each new command, rather than scanning through all the Outgoing
-    Mailboxes to find any that have new commands in them.  BusLogic indicates
-    that Strict Round Robin Mode is significantly more efficient.
+    Enable Strict Round Robin Mode if supported by the Host Adapter.  In
+    Strict Round Robin Mode, the Host Adapter only looks at the next Outgoing
+    Mailbox for each new command, rather than scanning through all the
+    Outgoing Mailboxes to find any that have new commands in them.  Strict
+    Round Robin Mode is significantly more efficient.
   */
-  if (strcmp(HostAdapter->FirmwareVersion, "3.31") >= 0)
+  if (HostAdapter->StrictRoundRobinModeSupported)
     {
       RoundRobinModeRequest = BusLogic_StrictRoundRobinMode;
       if (BusLogic_Command(HostAdapter, BusLogic_EnableStrictRoundRobinMode,
@@ -1360,7 +1604,7 @@
     }
   /*
     For Wide SCSI Host Adapters, issue the Enable Wide Mode CCB command to
-    allow more than 8 Logical Units per Target to be supported.
+    allow more than 8 Logical Units per Target Device to be supported.
   */
   if (HostAdapter->HostWideSCSI)
     {
@@ -1410,16 +1654,16 @@
 static boolean BusLogic_InquireTargetDevices(BusLogic_HostAdapter_T
 					     *HostAdapter)
 {
+  BusLogic_InstalledDevices_T InstalledDevices;
   BusLogic_InstalledDevices8_T InstalledDevicesID0to7;
-  BusLogic_InstalledDevices8_T InstalledDevicesID8to15;
   BusLogic_SetupInformation_T SetupInformation;
   BusLogic_SynchronousPeriod_T SynchronousPeriod;
   BusLogic_RequestedReplyLength_T RequestedReplyLength;
   int TargetDevicesFound = 0, TargetID;
   /*
     Wait a few seconds between the Host Adapter Hard Reset which initiates
-    a SCSI Bus Reset and issuing any SCSI commands.  Some SCSI devices get
-    confused if they receive SCSI commands too soon after a SCSI Bus Reset.
+    a SCSI Bus Reset and issuing any SCSI Commands.  Some SCSI devices get
+    confused if they receive SCSI Commands too soon after a SCSI Bus Reset.
   */
   BusLogic_Delay(HostAdapter->BusSettleTime);
   /*
@@ -1432,24 +1676,34 @@
       return true;
     }
   /*
-    Issue the Inquire Installed Devices ID 0 to 7 command, and for Wide SCSI
-    Host Adapters the Inquire Installed Devices ID 8 to 15 command.  This is
-    necessary to force Synchronous Transfer Negotiation so that the Inquire
-    Setup Information and Inquire Synchronous Period commands will return
-    valid data.
-  */
-  if (BusLogic_Command(HostAdapter, BusLogic_InquireInstalledDevicesID0to7,
-		       NULL, 0, &InstalledDevicesID0to7,
-		       sizeof(InstalledDevicesID0to7))
-      != sizeof(InstalledDevicesID0to7))
-    return BusLogic_Failure(HostAdapter, "INQUIRE INSTALLED DEVICES ID 0 TO 7");
-  if (HostAdapter->HostWideSCSI)
-    if (BusLogic_Command(HostAdapter, BusLogic_InquireInstalledDevicesID8to15,
-			 NULL, 0, &InstalledDevicesID8to15,
-			 sizeof(InstalledDevicesID8to15))
-	!= sizeof(InstalledDevicesID8to15))
-      return BusLogic_Failure(HostAdapter,
-			      "INQUIRE INSTALLED DEVICES ID 8 TO 15");
+    Issue the Inquire Devices command for "W" and "C" Series boards or the
+    Inquire Installed Devices ID 0 to 7 command for "S" and "A" Series boards.
+    This is necessary to force Synchronous Transfer Negotiation so that the
+    Inquire Setup Information and Inquire Synchronous Period commands will
+    return valid data.  The Inquire Devices command is preferable to Inquire
+    Installed Devices ID 0 to 7 since it only probes Logical Unit 0 of each
+    Target Device.
+  */
+  if (HostAdapter->FirmwareVersion[0] >= '4')
+    {
+      if (BusLogic_Command(HostAdapter, BusLogic_InquireDevices, NULL, 0,
+			   &InstalledDevices, sizeof(InstalledDevices))
+	  != sizeof(InstalledDevices))
+	return BusLogic_Failure(HostAdapter, "INQUIRE DEVICES");
+    }
+  else
+    {
+      if (BusLogic_Command(HostAdapter, BusLogic_InquireInstalledDevicesID0to7,
+			   NULL, 0, &InstalledDevicesID0to7,
+			   sizeof(InstalledDevicesID0to7))
+	  != sizeof(InstalledDevicesID0to7))
+	return BusLogic_Failure(HostAdapter,
+				"INQUIRE INSTALLED DEVICES ID 0 TO 7");
+      InstalledDevices = 0;
+      for (TargetID = 0; TargetID < 8; TargetID++)
+	if (InstalledDevicesID0to7[TargetID] != 0)
+	  InstalledDevices |= (1 << TargetID);
+    }
   /*
     Issue the Inquire Setup Information command.
   */
@@ -1472,7 +1726,7 @@
 	return BusLogic_Failure(HostAdapter, "INQUIRE SYNCHRONOUS PERIOD");
     }
   else
-    for (TargetID = 0; TargetID < HostAdapter->MaxTargetIDs; TargetID++)
+    for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
       if (SetupInformation.SynchronousValuesID0to7[TargetID].Offset > 0)
 	SynchronousPeriod[TargetID] =
 	  20 + 5 * SetupInformation.SynchronousValuesID0to7[TargetID]
@@ -1482,23 +1736,21 @@
     Save the Installed Devices, Synchronous Values, and Synchronous Period
     information in the Host Adapter structure.
   */
-  memcpy(HostAdapter->InstalledDevices, InstalledDevicesID0to7,
-	 sizeof(BusLogic_InstalledDevices8_T));
+  HostAdapter->InstalledDevices = InstalledDevices;
   memcpy(HostAdapter->SynchronousValues,
 	 SetupInformation.SynchronousValuesID0to7,
 	 sizeof(BusLogic_SynchronousValues8_T));
   if (HostAdapter->HostWideSCSI)
-    {
-      memcpy(&HostAdapter->InstalledDevices[8], InstalledDevicesID8to15,
-	     sizeof(BusLogic_InstalledDevices8_T));
-      memcpy(&HostAdapter->SynchronousValues[8],
-	     SetupInformation.SynchronousValuesID8to15,
-	     sizeof(BusLogic_SynchronousValues8_T));
-    }
+    memcpy(&HostAdapter->SynchronousValues[8],
+	   SetupInformation.SynchronousValuesID8to15,
+	   sizeof(BusLogic_SynchronousValues8_T));
   memcpy(HostAdapter->SynchronousPeriod, SynchronousPeriod,
 	 sizeof(BusLogic_SynchronousPeriod_T));
-  for (TargetID = 0; TargetID < HostAdapter->MaxTargetIDs; TargetID++)
-    if (HostAdapter->InstalledDevices[TargetID] != 0)
+  /*
+    Report on the Target Devices found.
+  */
+  for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+    if (HostAdapter->InstalledDevices & (1 << TargetID))
       {
 	int SynchronousPeriod = HostAdapter->SynchronousPeriod[TargetID];
 	if (SynchronousPeriod > 10)
@@ -1539,6 +1791,75 @@
 
 
 /*
+  BusLogic_InitializeHostStructure initializes the fields in the SCSI Host
+  structure.  The base, io_port, n_io_ports, irq, and dma_channel fields in the
+  SCSI Host structure are intentionally left uninitialized, as this driver
+  handles acquisition and release of these resources explicitly, as well as
+  ensuring exclusive access to the Host Adapter hardware and data structures
+  through explicit acquisition and release of the Host Adapter's Lock.
+*/
+
+static void BusLogic_InitializeHostStructure(BusLogic_HostAdapter_T
+					       *HostAdapter,
+					     SCSI_Host_T *Host)
+{
+  Host->max_id = HostAdapter->MaxTargetDevices;
+  Host->max_lun = HostAdapter->MaxLogicalUnits;
+  Host->max_channel = 0;
+  Host->unique_id = HostAdapter->IO_Address;
+  Host->this_id = HostAdapter->SCSI_ID;
+  Host->can_queue = HostAdapter->MailboxCount;
+  Host->sg_tablesize = HostAdapter->DriverScatterGatherLimit;
+  Host->unchecked_isa_dma = HostAdapter->BounceBuffersRequired;
+  Host->cmd_per_lun = HostAdapter->UntaggedQueueDepth;
+}
+
+
+/*
+  BusLogic_SelectQueueDepths selects Queue Depths for each Target Device
+  based on the Host Adapter's Total Queue Depth and the number, type, speed,
+  and capabilities of the Target Devices.
+*/
+
+static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host,
+				       SCSI_Device_T *DeviceList)
+{
+  BusLogic_HostAdapter_T *HostAdapter =
+    (BusLogic_HostAdapter_T *) Host->hostdata;
+  int TaggedQueueDepth = HostAdapter->TaggedQueueDepth;
+  int UntaggedQueueDepth = HostAdapter->UntaggedQueueDepth;
+  int TaggedDeviceCount = 0, UntaggedDeviceCount = 0;
+  SCSI_Device_T *Device;
+  for (Device = DeviceList; Device != NULL; Device = Device->next)
+    if (Device->host == Host)
+      {
+	if (Device->tagged_supported &&
+	    (HostAdapter->TaggedQueuingPermitted & (1 << Device->id)))
+	  TaggedDeviceCount++;
+	else UntaggedDeviceCount++;
+      }
+  if (TaggedQueueDepth == 0 && TaggedDeviceCount > 0)
+    TaggedQueueDepth =
+      1 + ((HostAdapter->TotalQueueDepth
+	    - UntaggedDeviceCount * UntaggedQueueDepth)
+	   / TaggedDeviceCount);
+  if (TaggedQueueDepth > BusLogic_MaxTaggedQueueDepth)
+    TaggedQueueDepth = BusLogic_MaxTaggedQueueDepth;
+  for (Device = DeviceList; Device != NULL; Device = Device->next)
+    if (Device->host == Host)
+      {
+	if (Device->tagged_supported &&
+	    (HostAdapter->TaggedQueuingPermitted & (1 << Device->id)))
+	  Device->queue_depth = TaggedQueueDepth;
+	else Device->queue_depth = UntaggedQueueDepth;
+	if (BusLogic_GlobalOptions & BusLogic_TraceQueueDepths)
+	  printk("scsi%d: Setting Queue Depth for Target %d to %d\n",
+		 HostAdapter->HostNumber, Device->id, Device->queue_depth);
+      }
+}
+
+
+/*
   BusLogic_DetectHostAdapter probes for BusLogic Host Adapters at the standard
   I/O Addresses where they may be located, initializing, registering, and
   reporting the configuration of each BusLogic Host Adapter it finds.  It
@@ -1619,6 +1940,7 @@
 	     sizeof(BusLogic_HostAdapter_T));
       HostAdapter->SCSI_Host = Host;
       HostAdapter->HostNumber = Host->host_no;
+      Host->select_queue_depths = BusLogic_SelectQueueDepths;
       /*
 	Add Host Adapter to the end of the list of registered BusLogic
 	Host Adapters.  In order for Command Complete Interrupts to be
@@ -1632,12 +1954,14 @@
       /*
 	Read the Host Adapter Configuration, Acquire the System Resources
 	necessary to use Host Adapter and initialize the fields in the SCSI
-	Host structure, then Test Interrupts, Create the CCBs, Initialize
-	the Host Adapter, and finally Inquire about the Target Devices.
+	Host structure, then Test Interrupts, Create the Mailboxes and CCBs,
+	Initialize the Host Adapter, and finally Inquire about the Target
+	Devices.
       */
       if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) &&
-	  BusLogic_AcquireResources(HostAdapter, Host) &&
+	  BusLogic_AcquireResources(HostAdapter) &&
 	  BusLogic_TestInterrupts(HostAdapter) &&
+	  BusLogic_CreateMailboxes(HostAdapter) &&
 	  BusLogic_CreateCCBs(HostAdapter) &&
 	  BusLogic_InitializeHostAdapter(HostAdapter) &&
 	  BusLogic_InquireTargetDevices(HostAdapter))
@@ -1645,24 +1969,27 @@
 	  /*
 	    Initialization has been completed successfully.  Release and
 	    re-register usage of the I/O Address range so that the Model
-	    Name of the Host Adapter will appear.
+	    Name of the Host Adapter will appear, and initialize the SCSI
+	    Host structure.
 	  */
 	  release_region(HostAdapter->IO_Address, BusLogic_IO_PortCount);
 	  request_region(HostAdapter->IO_Address, BusLogic_IO_PortCount,
 			 HostAdapter->BoardName);
+	  BusLogic_InitializeHostStructure(HostAdapter, Host);
 	  BusLogicHostAdapterCount++;
 	}
       else
 	{
 	  /*
 	    An error occurred during Host Adapter Configuration Querying,
-	    Resource Acquisition, Interrupt Testing, CCB Creation, Host
-	    Adapter Initialization, or Target Device Inquiry, so remove
-	    Host Adapter from the list of registered BusLogic Host Adapters,
-	    destroy the CCBs, Release the System Resources, and Unregister
+	    Resource Acquisition, Interrupt Testing, CCB Creation, Host Adapter
+	    Initialization, or Target Device Inquiry, so remove Host Adapter
+	    from the list of registered BusLogic Host Adapters, destroy the
+	    CCBs and Mailboxes, Release the System Resources, and Unregister
 	    the SCSI Host.
 	  */
 	  BusLogic_DestroyCCBs(HostAdapter);
+	  BusLogic_DestroyMailboxes(HostAdapter);
 	  BusLogic_ReleaseResources(HostAdapter);
 	  BusLogic_UnregisterHostAdapter(HostAdapter);
 	  scsi_unregister(Host);
@@ -1683,10 +2010,11 @@
   BusLogic_HostAdapter_T *HostAdapter =
     (BusLogic_HostAdapter_T *) Host->hostdata;
   /*
-    Destroy the CCBs and release any system resources acquired to use
-    Host Adapter.
+    Destroy the CCBs and Mailboxes, and release any system resources acquired
+    to support Host Adapter.
   */
   BusLogic_DestroyCCBs(HostAdapter);
+  BusLogic_DestroyMailboxes(HostAdapter);
   BusLogic_ReleaseResources(HostAdapter);
   /*
     Release usage of the I/O Address range.
@@ -1770,11 +2098,12 @@
 {
   BusLogic_CCB_T *FirstCompletedCCB = NULL, *LastCompletedCCB = NULL;
   BusLogic_HostAdapter_T *HostAdapter;
-  int HostAdapterResetPendingCount = 0;
+  int HostAdapterResetRequestedCount = 0;
+  BusLogic_Lock_T Lock;
   /*
     Iterate over the installed BusLogic Host Adapters accepting any Incoming
     Mailbox entries and saving the completed CCBs for processing.  This
-    interrupt handler is installed with SA_INTERRUPT, so interrupts are
+    interrupt handler is installed as a fast interrupt, so interrupts are
     disabled when the interrupt handler is entered.
   */
   for (HostAdapter = BusLogic_RegisteredHostAdapters;
@@ -1785,7 +2114,7 @@
       /*
 	Acquire exclusive access to Host Adapter.
       */
-      BusLogic_LockHostAdapterID(HostAdapter);
+      BusLogic_AcquireHostAdapterLockID(HostAdapter, &Lock);
       /*
 	Read the Host Adapter Interrupt Register.
       */
@@ -1799,14 +2128,14 @@
 	  BusLogic_WriteControlRegister(HostAdapter, BusLogic_InterruptReset);
 	  /*
 	    Process valid SCSI Reset State and Incoming Mailbox Loaded
-	    interrupts.  Command Complete interrupts are noted, and
-	    Outgoing Mailbox Available interrupts are ignored, as they
+	    Interrupts.  Command Complete Interrupts are noted, and
+	    Outgoing Mailbox Available Interrupts are ignored, as they
 	    are never enabled.
 	  */
 	  if (InterruptRegister & BusLogic_SCSIResetState)
 	    {
-	      HostAdapter->HostAdapterResetPending = true;
-	      HostAdapterResetPendingCount++;
+	      HostAdapter->HostAdapterResetRequested = true;
+	      HostAdapterResetRequestedCount++;
 	    }
 	  else if (InterruptRegister & BusLogic_IncomingMailboxLoaded)
 	    {
@@ -1833,7 +2162,8 @@
 		{
 		  BusLogic_CCB_T *CCB = NextIncomingMailbox->CCB;
 		  if (MailboxCompletionCode != BusLogic_AbortedCommandNotFound)
-		    if (CCB->Status == BusLogic_CCB_Active)
+		    if (CCB->Status == BusLogic_CCB_Active ||
+			CCB->Status == BusLogic_CCB_Reset)
 		      {
 			/*
 			  Mark this CCB as completed and add it to the end
@@ -1852,14 +2182,14 @@
 			    LastCompletedCCB->Next = CCB;
 			    LastCompletedCCB = CCB;
 			  }
-			HostAdapter->QueuedOperationCount[CCB->TargetID]--;
+			HostAdapter->ActiveCommandCount[CCB->TargetID]--;
 		      }
 		    else
 		      {
 			/*
 			  If a CCB ever appears in an Incoming Mailbox and
-			  is not marked as status Active, then there is
-			  most likely a bug in the Host Adapter firmware.
+			  is not marked as status Active or Reset, then there
+			  is most likely a bug in the Host Adapter firmware.
 			*/
 			printk("scsi%d: Illegal CCB #%d status %d in "
 			       "Incoming Mailbox\n", HostAdapter->HostNumber,
@@ -1881,26 +2211,9 @@
       /*
 	Release exclusive access to Host Adapter.
       */
-      BusLogic_UnlockHostAdapterID(HostAdapter);
+      BusLogic_ReleaseHostAdapterLockID(HostAdapter, &Lock);
     }
   /*
-    Enable interrupts while the completed CCBs are processed.
-  */
-  sti();
-  /*
-    Iterate over the Host Adapters performing any pending Host Adapter Resets.
-  */
-  if (HostAdapterResetPendingCount > 0)
-    for (HostAdapter = BusLogic_RegisteredHostAdapters;
-	 HostAdapter != NULL;
-	 HostAdapter = HostAdapter->Next)
-      if (HostAdapter->HostAdapterResetPending)
-	{
-	  BusLogic_ResetHostAdapter(HostAdapter, NULL);
-	  HostAdapter->HostAdapterResetPending = false;
-	  scsi_mark_host_bus_reset(HostAdapter->SCSI_Host);
-	}
-  /*
     Iterate over the completed CCBs setting the SCSI Command Result Codes,
     deallocating the CCBs, and calling the Completion Routines.
   */
@@ -1911,77 +2224,133 @@
       FirstCompletedCCB = FirstCompletedCCB->Next;
       HostAdapter = CCB->HostAdapter;
       /*
-	Bus Device Reset CCBs have the Command field non-NULL only when a Bus
-	Device Reset was requested for a command that was not currently active
-	in the Host Adapter, and hence would not have its Completion Routine
-	called otherwise.
+	Acquire exclusive access to Host Adapter.
+      */
+      BusLogic_AcquireHostAdapterLockID(HostAdapter, &Lock);
+      /*
+	Process the Completed CCB.
       */
-      if (CCB->Opcode == BusLogic_SCSIBusDeviceReset)
+      if (CCB->Opcode == BusLogic_BusDeviceReset)
 	{
+	  unsigned char TargetID = CCB->TargetID;
 	  printk("scsi%d: Bus Device Reset CCB #%d to Target %d Completed\n",
-		 HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID);
-	  if (Command != NULL) Command->result = DID_RESET << 16;
+		 HostAdapter->HostNumber, CCB->SerialNumber, TargetID);
+	  HostAdapter->TotalCommandCount[TargetID] = 0;
+	  HostAdapter->TaggedQueuingActive[TargetID] = false;
+	  /*
+	    Place CCB back on the Host Adapter's free list.
+	  */
+	  BusLogic_DeallocateCCB(CCB);
+	  /*
+	    Bus Device Reset CCBs have the Command field non-NULL only when a
+	    Bus Device Reset was requested for a Command that did not have a
+	    currently active CCB in the Host Adapter (i.e., a Synchronous
+	    Bus Device Reset), and hence would not have its Completion Routine
+	    called otherwise.
+	  */
+	  while (Command != NULL)
+	    {
+	      SCSI_Command_T *NextCommand = Command->reset_chain;
+	      Command->reset_chain = NULL;
+	      Command->result = DID_RESET << 16;
+	      Command->scsi_done(Command);
+	      Command = NextCommand;
+	    }
+	  /*
+	    Iterate over the CCBs for this Host Adapter performing completion
+	    processing for any CCBs marked as Reset for this Target.
+	  */
+	  for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll)
+	    if (CCB->Status == BusLogic_CCB_Reset && CCB->TargetID == TargetID)
+	      {
+		Command = CCB->Command;
+		BusLogic_DeallocateCCB(CCB);
+		HostAdapter->ActiveCommandCount[TargetID]--;
+		Command->result = DID_RESET << 16;
+		Command->scsi_done(Command);
+	      }
+	  HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL;
 	}
       else
-	/*
-	  Translate the Mailbox Completion Code, Host Adapter Status, and
-	  Target Device Status into a SCSI Subsystem Result Code.
-	*/
-	switch (CCB->MailboxCompletionCode)
-	  {
-	  case BusLogic_IncomingMailboxFree:
-	  case BusLogic_AbortedCommandNotFound:
-	    printk("scsi%d: CCB #%d to Target %d Impossible State\n",
-		   HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID);
-	    break;
-	  case BusLogic_CommandCompletedWithoutError:
-	    HostAdapter->CommandSuccessfulFlag[CCB->TargetID] = true;
-	    Command->result = DID_OK << 16;
-	    break;
-	  case BusLogic_CommandAbortedAtHostRequest:
-	    printk("scsi%d: CCB #%d to Target %d Aborted\n",
-		   HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID);
-	    Command->result = DID_ABORT << 16;
-	    break;
-	  case BusLogic_CommandCompletedWithError:
-	    Command->result =
-	      BusLogic_ComputeResultCode(CCB->HostAdapterStatus,
-					 CCB->TargetDeviceStatus);
-	    if (BusLogic_GlobalOptions & BusLogic_TraceErrors)
-	      if (CCB->HostAdapterStatus != BusLogic_SCSISelectionTimeout)
-		{
-		  int i;
-		  printk("scsi%d: CCB #%d Target %d: Result %X "
-			 "Host Adapter Status %02X Target Status %02X\n",
-			 HostAdapter->HostNumber, CCB->SerialNumber,
-			 CCB->TargetID, Command->result,
-			 CCB->HostAdapterStatus, CCB->TargetDeviceStatus);
-		  printk("scsi%d: CDB   ", HostAdapter->HostNumber);
-		  for (i = 0; i < CCB->CDB_Length; i++)
-		    printk(" %02X", CCB->CDB[i]);
-		  printk("\n");
-		  printk("scsi%d: Sense ", HostAdapter->HostNumber);
-		  for (i = 0; i < CCB->SenseDataLength; i++)
-		    printk(" %02X", (*CCB->SenseDataPointer)[i]);
-		  printk("\n");
-		}
-	    break;
-	  }
-      /*
-	Place CCB back on the Host Adapter's free list.
-      */
-      BusLogic_DeallocateCCB(CCB);
+	{
+	  /*
+	    Translate the Mailbox Completion Code, Host Adapter Status, and
+	    Target Device Status into a SCSI Subsystem Result Code.
+	  */
+	  switch (CCB->MailboxCompletionCode)
+	    {
+	    case BusLogic_IncomingMailboxFree:
+	    case BusLogic_AbortedCommandNotFound:
+	      printk("scsi%d: CCB #%d to Target %d Impossible State\n",
+		     HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID);
+	      break;
+	    case BusLogic_CommandCompletedWithoutError:
+	      HostAdapter->CommandSuccessfulFlag[CCB->TargetID] = true;
+	      Command->result = DID_OK << 16;
+	      break;
+	    case BusLogic_CommandAbortedAtHostRequest:
+	      printk("scsi%d: CCB #%d to Target %d Aborted\n",
+		     HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID);
+	      Command->result = DID_ABORT << 16;
+	      break;
+	    case BusLogic_CommandCompletedWithError:
+	      Command->result =
+		BusLogic_ComputeResultCode(CCB->HostAdapterStatus,
+					   CCB->TargetDeviceStatus);
+	      if (BusLogic_GlobalOptions & BusLogic_TraceErrors)
+		if (CCB->HostAdapterStatus != BusLogic_SCSISelectionTimeout)
+		  {
+		    int i;
+		    printk("scsi%d: CCB #%d Target %d: Result %X "
+			   "Host Adapter Status %02X Target Status %02X\n",
+			   HostAdapter->HostNumber, CCB->SerialNumber,
+			   CCB->TargetID, Command->result,
+			   CCB->HostAdapterStatus, CCB->TargetDeviceStatus);
+		    printk("scsi%d: CDB   ", HostAdapter->HostNumber);
+		    for (i = 0; i < CCB->CDB_Length; i++)
+		      printk(" %02X", CCB->CDB[i]);
+		    printk("\n");
+		    printk("scsi%d: Sense ", HostAdapter->HostNumber);
+		    for (i = 0; i < CCB->SenseDataLength; i++)
+		      printk(" %02X", (*CCB->SenseDataPointer)[i]);
+		    printk("\n");
+		  }
+	      break;
+	    }
+	  /*
+	    Place CCB back on the Host Adapter's free list.
+	  */
+	  BusLogic_DeallocateCCB(CCB);
+	  /*
+	    Call the SCSI Command Completion Routine.
+	  */
+	  Command->scsi_done(Command);
+	}
       /*
-	Call the SCSI Command Completion Routine if appropriate.
+	Release exclusive access to Host Adapter.
       */
-      if (Command != NULL) Command->scsi_done(Command);
+      BusLogic_ReleaseHostAdapterLockID(HostAdapter, &Lock);
     }
+  /*
+    Iterate over the Host Adapters performing any requested Host Adapter Resets.
+  */
+  if (HostAdapterResetRequestedCount == 0) return;
+  for (HostAdapter = BusLogic_RegisteredHostAdapters;
+       HostAdapter != NULL;
+       HostAdapter = HostAdapter->Next)
+    if (HostAdapter->HostAdapterResetRequested)
+      {
+	BusLogic_ResetHostAdapter(HostAdapter, NULL, 0);
+	HostAdapter->HostAdapterResetRequested = false;
+	scsi_mark_host_bus_reset(HostAdapter->SCSI_Host);
+      }
 }
 
 
 /*
   BusLogic_WriteOutgoingMailbox places CCB and Action Code into an Outgoing
-  Mailbox for execution by Host Adapter.
+  Mailbox for execution by Host Adapter.  The Host Adapter's Lock should have
+  already been acquired by the caller.
 */
 
 static boolean BusLogic_WriteOutgoingMailbox(BusLogic_HostAdapter_T
@@ -1990,8 +2359,6 @@
 					     BusLogic_CCB_T *CCB)
 {
   BusLogic_OutgoingMailbox_T *NextOutgoingMailbox;
-  boolean Result = false;
-  BusLogic_LockHostAdapter(HostAdapter);
   NextOutgoingMailbox = HostAdapter->NextOutgoingMailbox;
   if (NextOutgoingMailbox->ActionCode == BusLogic_OutgoingMailboxFree)
     {
@@ -2003,16 +2370,15 @@
       */
       NextOutgoingMailbox->CCB = CCB;
       NextOutgoingMailbox->ActionCode = ActionCode;
-      BusLogic_StartMailboxScan(HostAdapter);
+      BusLogic_StartMailboxCommand(HostAdapter);
       if (++NextOutgoingMailbox > HostAdapter->LastOutgoingMailbox)
 	NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox;
       HostAdapter->NextOutgoingMailbox = NextOutgoingMailbox;
       if (ActionCode == BusLogic_MailboxStartCommand)
-	HostAdapter->QueuedOperationCount[CCB->TargetID]++;
-      Result = true;
+	HostAdapter->ActiveCommandCount[CCB->TargetID]++;
+      return true;
     }
-  BusLogic_UnlockHostAdapter(HostAdapter);
-  return Result;
+  return false;
 }
 
 
@@ -2033,8 +2399,8 @@
   void *BufferPointer = Command->request_buffer;
   int BufferLength = Command->request_bufflen;
   int SegmentCount = Command->use_sg;
+  BusLogic_Lock_T Lock;
   BusLogic_CCB_T *CCB;
-  long EnableTQ;
   /*
     SCSI REQUEST_SENSE commands will be executed automatically by the Host
     Adapter for any errors, so they should not be executed explicitly unless
@@ -2047,16 +2413,26 @@
       return 0;
     }
   /*
-    Allocate a CCB from the Host Adapter's free list.  If there are none
-    available and memory allocation fails, return a result code of Bus Busy
-    so that this Command will be retried.
+    Acquire exclusive access to Host Adapter.
+  */
+  BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+  /*
+    Allocate a CCB from the Host Adapter's free list.  In the unlikely event
+    that there are none available and memory allocation fails, wait 1 second
+    and try again.  If that fails, the Host Adapter is probably hung so we
+    signal an error as a Host Adapter Hard Reset should be initiated soon.
   */
   CCB = BusLogic_AllocateCCB(HostAdapter);
   if (CCB == NULL)
     {
-      Command->result = DID_BUS_BUSY << 16;
-      CompletionRoutine(Command);
-      return 0;
+      BusLogic_Delay(1);
+      CCB = BusLogic_AllocateCCB(HostAdapter);
+      if (CCB == NULL)
+	{
+	  Command->result = DID_ERROR << 16;
+	  CompletionRoutine(Command);
+	  goto Done;
+	}
     }
   /*
     Initialize the fields in the BusLogic Command Control Block (CCB).
@@ -2087,12 +2463,10 @@
     case READ_6:
     case READ_10:
       CCB->DataDirection = BusLogic_DataInLengthChecked;
-      HostAdapter->ReadWriteOperationCount[TargetID]++;
       break;
     case WRITE_6:
     case WRITE_10:
       CCB->DataDirection = BusLogic_DataOutLengthChecked;
-      HostAdapter->ReadWriteOperationCount[TargetID]++;
       break;
     default:
       CCB->DataDirection = BusLogic_UncheckedDataTransfer;
@@ -2117,22 +2491,27 @@
   else CCB->TagEnable = false;
   /*
     BusLogic recommends that after a Reset the first couple of commands that
-    are sent to a Target be sent in a non Tagged Queue fashion so that the Host
-    Adapter and Target can establish Synchronous Transfer before Queue Tag
-    messages can interfere with the Synchronous Negotiation message.  By
-    waiting to enable tagged Queuing until after the first 16 read/write
-    commands have been sent, it is assured that the Tagged Queuing message
-    will not occur while the partition table is printed.
-  */
-  if ((HostAdapter->TaggedQueuingPermitted & (1 << TargetID)) &&
-      Command->device->tagged_supported &&
-      (EnableTQ = HostAdapter->ReadWriteOperationCount[TargetID] - 16) >= 0)
+    are sent to a Target Device be sent in a non Tagged Queue fashion so that
+    the Host Adapter and Target Device can establish Synchronous and Wide
+    Transfer before Queue Tag messages can interfere with the Synchronous and
+    Wide Negotiation message.  By waiting to enable Tagged Queuing until after
+    the first BusLogic_MaxTaggedQueueDepth commands have been sent, it is
+    assured that after a Reset any pending commands are resent before Tagged
+    Queuing is enabled and that the Tagged Queuing message will not occur while
+    the partition table is being printed.
+  */
+  if (HostAdapter->TotalCommandCount[TargetID]++ ==
+        BusLogic_MaxTaggedQueueDepth &&
+      (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)) &&
+      Command->device->tagged_supported)
+    {
+      HostAdapter->TaggedQueuingActive[TargetID] = true;
+      printk("scsi%d: Tagged Queuing now active for Target %d\n",
+	     HostAdapter->HostNumber, TargetID);
+    }
+  if (HostAdapter->TaggedQueuingActive[TargetID])
     {
       BusLogic_QueueTag_T QueueTag = BusLogic_SimpleQueueTag;
-      unsigned long CurrentTime = jiffies;
-      if (EnableTQ == 0)
-	printk("scsi%d: Tagged Queuing now active for Target %d\n",
-	       HostAdapter->HostNumber, TargetID);
       /*
 	When using Tagged Queuing with Simple Queue Tags, it appears that disk
 	drive controllers do not guarantee that a queued command will not
@@ -2140,16 +2519,17 @@
 	write nearer the head position continue to arrive without interruption.
 	Therefore, for each Target Device this driver keeps track of the last
 	time either the queue was empty or an Ordered Queue Tag was issued.  If
-	more than 2 seconds have elapsed since this last sequence point, this
-	command will be issued with an Ordered Queue Tag rather than a Simple
-	Queue Tag, which forces the Target Device to complete all previously
-	queued commands before this command may be executed.
-      */
-      if (HostAdapter->QueuedOperationCount[TargetID] == 0)
-	HostAdapter->LastSequencePoint[TargetID] = CurrentTime;
-      else if (CurrentTime - HostAdapter->LastSequencePoint[TargetID] > 2*HZ)
+	more than 5 seconds (half the 10 second disk timeout) have elapsed
+	since this last sequence point, this command will be issued with an
+	Ordered Queue Tag rather than a Simple Queue Tag, which forces the
+	Target Device to complete all previously queued commands before this
+	command may be executed.
+      */
+      if (HostAdapter->ActiveCommandCount[TargetID] == 0)
+	HostAdapter->LastSequencePoint[TargetID] = jiffies;
+      else if (jiffies - HostAdapter->LastSequencePoint[TargetID] > 5*HZ)
 	{
-	  HostAdapter->LastSequencePoint[TargetID] = CurrentTime;
+	  HostAdapter->LastSequencePoint[TargetID] = jiffies;
 	  QueueTag = BusLogic_OrderedQueueTag;
 	}
       if (HostAdapter->HostWideSCSI)
@@ -2168,19 +2548,34 @@
   CCB->Command = Command;
   Command->scsi_done = CompletionRoutine;
   /*
-    Place the CCB in an Outgoing Mailbox.  If there are no Outgoing
-    Mailboxes available, return a result code of Bus Busy so that this
-    Command will be retried.
+    Place the CCB in an Outgoing Mailbox.  The higher levels of the SCSI
+    Subsystem should not attempt to queue more commands than can be placed in
+    Outgoing Mailboxes, so there should always be one free.  In the unlikely
+    event that there are none available, wait 1 second and try again.  If
+    that fails, the Host Adapter is probably hung so we signal an error as
+    a Host Adapter Hard Reset should be initiated soon.
   */
-  if (!(BusLogic_WriteOutgoingMailbox(HostAdapter,
-				      BusLogic_MailboxStartCommand, CCB)))
+  if (!BusLogic_WriteOutgoingMailbox(HostAdapter,
+				     BusLogic_MailboxStartCommand, CCB))
     {
-      printk("scsi%d: cannot write Outgoing Mailbox\n",
+      printk("scsi%d: cannot write Outgoing Mailbox - Pausing for 1 second\n",
 	     HostAdapter->HostNumber);
-      BusLogic_DeallocateCCB(CCB);
-      Command->result = DID_BUS_BUSY << 16;
-      CompletionRoutine(Command);
+      BusLogic_Delay(1);
+      if (!BusLogic_WriteOutgoingMailbox(HostAdapter,
+					 BusLogic_MailboxStartCommand, CCB))
+	{
+	  printk("scsi%d: still cannot write Outgoing Mailbox - "
+		 "Host Adapter Dead?\n", HostAdapter->HostNumber);
+	  BusLogic_DeallocateCCB(CCB);
+	  Command->result = DID_ERROR << 16;
+	  Command->scsi_done(Command);
+	}
     }
+  /*
+    Release exclusive access to Host Adapter.
+  */
+Done:
+  BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
   return 0;
 }
 
@@ -2193,92 +2588,148 @@
 {
   BusLogic_HostAdapter_T *HostAdapter =
     (BusLogic_HostAdapter_T *) Command->host->hostdata;
-  unsigned long CommandPID = Command->pid;
-  unsigned char InterruptRegister;
+  unsigned char TargetID = Command->target;
+  BusLogic_Lock_T Lock;
   BusLogic_CCB_T *CCB;
   int Result;
   /*
-    If the Host Adapter has posted an interrupt but the Interrupt Handler
-    has not been called for some reason (i.e. the interrupt was lost), try
-    calling the Interrupt Handler directly to process the commands that
-    have been completed.
-  */
-  InterruptRegister = BusLogic_ReadInterruptRegister(HostAdapter);
-  if (InterruptRegister & BusLogic_InterruptValid)
-    {
-      unsigned long ProcessorFlags;
-      printk("scsi%d: Recovering Lost/Delayed Interrupt for IRQ Channel %d\n",
-	     HostAdapter->HostNumber, HostAdapter->IRQ_Channel);
-      save_flags(ProcessorFlags);
-      cli();
-      BusLogic_InterruptHandler(HostAdapter->IRQ_Channel, NULL, NULL);
-      restore_flags(ProcessorFlags);
-      return SCSI_ABORT_SNOOZE;
+    Acquire exclusive access to Host Adapter.
+  */
+  BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+  /*
+    If this Command has already completed, then no Abort is necessary.
+  */
+  if (Command->serial_number != Command->serial_number_at_timeout)
+    {
+      printk("scsi%d: Unable to Abort Command to Target %d - "
+	     "Already Completed\n", HostAdapter->HostNumber, TargetID);
+      Result = SCSI_ABORT_NOT_RUNNING;
+      goto Done;
     }
   /*
-    Find the CCB to be aborted if possible.
+    Attempt to find an Active CCB for this Command.  If no Active CCB for this
+    Command is found, then no Abort is necessary.
   */
-  BusLogic_LockHostAdapter(HostAdapter);
   for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll)
     if (CCB->Command == Command) break;
-  BusLogic_UnlockHostAdapter(HostAdapter);
   if (CCB == NULL)
     {
       printk("scsi%d: Unable to Abort Command to Target %d - No CCB Found\n",
-	     HostAdapter->HostNumber, Command->target);
-      return SCSI_ABORT_NOT_RUNNING;
+	     HostAdapter->HostNumber, TargetID);
+      Result = SCSI_ABORT_NOT_RUNNING;
+      goto Done;
+    }
+  else if (CCB->Status == BusLogic_CCB_Completed)
+    {
+      printk("scsi%d: Unable to Abort Command to Target %d - CCB Completed\n",
+	     HostAdapter->HostNumber, TargetID);
+      Result = SCSI_ABORT_NOT_RUNNING;
+      goto Done;
+    }
+  else if (CCB->Status == BusLogic_CCB_Reset)
+    {
+      printk("scsi%d: Unable to Abort Command to Target %d - CCB Reset\n",
+	     HostAdapter->HostNumber, TargetID);
+      Result = SCSI_ABORT_NOT_RUNNING;
+      goto Done;
+    }
+  /*
+    Attempt to Abort this CCB.  Firmware versions prior to 5.xx do not generate
+    Abort Tag messages, but only generate the non-tagged Abort message.  Since
+    non-tagged commands are not sent by the Host Adapter until the queue of
+    outstanding tagged commands has completed, and the Abort message is treated
+    as a non-tagged command, it is effectively impossible to abort commands
+    when Tagged Queuing is active.  Firmware version 5.xx does generate Abort
+    Tag messages, so it is possible to abort commands when Tagged Queuing is
+    active.
+  */
+  if (HostAdapter->TaggedQueuingActive[TargetID] &&
+      HostAdapter->FirmwareVersion[0] < '5')
+    {
+      printk("scsi%d: Unable to Abort CCB #%d to Target %d - "
+	     "Abort Tag Not Supported\n", HostAdapter->HostNumber,
+	     CCB->SerialNumber, TargetID);
+      Result = SCSI_ABORT_SNOOZE;
+    }
+  else if (BusLogic_WriteOutgoingMailbox(HostAdapter,
+					 BusLogic_MailboxAbortCommand, CCB))
+    {
+      printk("scsi%d: Aborting CCB #%d to Target %d\n",
+	     HostAdapter->HostNumber, CCB->SerialNumber, TargetID);
+      Result = SCSI_ABORT_PENDING;
     }
-  /*
-    Briefly pause to see if this command will complete.
-  */
-  printk("scsi%d: Pausing briefly to see if CCB #%d "
-	 "to Target %d will complete\n",
-	 HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID);
-  BusLogic_Delay(2);
-  /*
-    If this CCB is still Active and still refers to the same Command, then
-    actually aborting this Command is necessary.
-  */
-  BusLogic_LockHostAdapter(HostAdapter);
-  Result = SCSI_ABORT_NOT_RUNNING;
-  if (CCB->Status == BusLogic_CCB_Active &&
-      CCB->Command == Command && Command->pid == CommandPID)
+  else
     {
-      /*
-	Attempt to abort this CCB.
-      */
-      if (BusLogic_WriteOutgoingMailbox(HostAdapter,
-					BusLogic_MailboxAbortCommand, CCB))
-	{
-	  printk("scsi%d: Aborting CCB #%d to Target %d\n",
-		 HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID);
-	  Result = SCSI_ABORT_PENDING;
-	}
-      else
-	{
-	  printk("scsi%d: Unable to Abort CCB #%d to Target %d - "
-		 "No Outgoing Mailboxes\n", HostAdapter->HostNumber,
-		 CCB->SerialNumber, CCB->TargetID);
-	  Result = SCSI_ABORT_BUSY;
-	}
+      printk("scsi%d: Unable to Abort CCB #%d to Target %d - "
+	     "No Outgoing Mailboxes\n", HostAdapter->HostNumber,
+	     CCB->SerialNumber, TargetID);
+      Result = SCSI_ABORT_BUSY;
     }
-  else printk("scsi%d: CCB #%d to Target %d completed\n",
-	      HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID);
-  BusLogic_UnlockHostAdapter(HostAdapter);
+  /*
+    Release exclusive access to Host Adapter.
+  */
+Done:
+  BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
   return Result;
 }
 
 
 /*
   BusLogic_ResetHostAdapter resets Host Adapter if possible, marking all
-  currently executing SCSI commands as having been reset, as well as
-  the specified Command if non-NULL.
+  currently executing SCSI Commands as having been Reset.
 */
 
 static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *HostAdapter,
-				     SCSI_Command_T *Command)
+				     SCSI_Command_T *Command,
+				     unsigned int ResetFlags)
 {
+  BusLogic_Lock_T Lock;
   BusLogic_CCB_T *CCB;
+  int TargetID, Result;
+  /*
+    Acquire exclusive access to Host Adapter.
+  */
+  BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+  /*
+    If this is an Asynchronous Reset and this Command has already completed,
+    then no Reset is necessary.
+  */
+  if (ResetFlags & SCSI_RESET_ASYNCHRONOUS)
+    {
+      TargetID = Command->target;
+      if (Command->serial_number != Command->serial_number_at_timeout)
+	{
+	  printk("scsi%d: Unable to Reset Command to Target %d - "
+		 "Already Completed or Reset\n",
+		 HostAdapter->HostNumber, TargetID);
+	  Result = SCSI_RESET_NOT_RUNNING;
+	  goto Done;
+      }
+      for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll)
+	if (CCB->Command == Command) break;
+      if (CCB == NULL)
+	{
+	  printk("scsi%d: Unable to Reset Command to Target %d - "
+		 "No CCB Found\n", HostAdapter->HostNumber, TargetID);
+	  Result = SCSI_RESET_NOT_RUNNING;
+	  goto Done;
+	}
+      else if (CCB->Status == BusLogic_CCB_Completed)
+	{
+	  printk("scsi%d: Unable to Reset Command to Target %d - "
+		 "CCB Completed\n", HostAdapter->HostNumber, TargetID);
+	  Result = SCSI_RESET_NOT_RUNNING;
+	  goto Done;
+	}
+      else if (CCB->Status == BusLogic_CCB_Reset &&
+	       HostAdapter->BusDeviceResetPendingCCB[TargetID] == NULL)
+	{
+	  printk("scsi%d: Unable to Reset Command to Target %d - "
+		 "Reset Pending\n", HostAdapter->HostNumber, TargetID);
+	  Result = SCSI_RESET_PENDING;
+	  goto Done;
+	}
+    }
   if (Command == NULL)
     printk("scsi%d: Resetting %s due to SCSI Reset State Interrupt\n",
 	   HostAdapter->HostNumber, HostAdapter->BoardName);
@@ -2287,121 +2738,166 @@
   /*
     Attempt to Reset and Reinitialize the Host Adapter.
   */
-  BusLogic_LockHostAdapter(HostAdapter);
   if (!(BusLogic_HardResetHostAdapter(HostAdapter) &&
 	BusLogic_InitializeHostAdapter(HostAdapter)))
     {
       printk("scsi%d: Resetting %s Failed\n",
 	      HostAdapter->HostNumber, HostAdapter->BoardName);
-      BusLogic_UnlockHostAdapter(HostAdapter);
-      return SCSI_RESET_ERROR;
+      Result = SCSI_RESET_ERROR;
+      goto Done;
     }
-  BusLogic_UnlockHostAdapter(HostAdapter);
-  /*
-    Wait a few seconds between the Host Adapter Hard Reset which initiates
-    a SCSI Bus Reset and issuing any SCSI commands.  Some SCSI devices get
-    confused if they receive SCSI commands too soon after a SCSI Bus Reset.
-  */
-  BusLogic_Delay(HostAdapter->BusSettleTime);
   /*
-    Mark all currently executing CCBs as having been reset.
+    Mark all currently executing CCBs as having been Reset.
   */
-  BusLogic_LockHostAdapter(HostAdapter);
   for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll)
     if (CCB->Status == BusLogic_CCB_Active)
-      {
-	CCB->Status = BusLogic_CCB_Reset;
-	if (CCB->Command == Command)
-	  {
-	    CCB->Command = NULL;
-	    /*
-	      Disable Tagged Queuing if it was active for this Target Device.
-	    */
-	    if (((HostAdapter->HostWideSCSI && CCB->WideModeTagEnable) ||
-		 (!HostAdapter->HostWideSCSI && CCB->TagEnable)) &&
-		(HostAdapter->TaggedQueuingPermitted & (1 << CCB->TargetID)))
-	      {
-		HostAdapter->TaggedQueuingPermitted &= ~(1 << CCB->TargetID);
-		printk("scsi%d: Tagged Queuing now disabled for Target %d\n",
-		       HostAdapter->HostNumber, CCB->TargetID);
-	      }
-	  }
-      }
-  BusLogic_UnlockHostAdapter(HostAdapter);
+      CCB->Status = BusLogic_CCB_Reset;
+  /*
+    Wait a few seconds between the Host Adapter Hard Reset which initiates
+    a SCSI Bus Reset and issuing any SCSI Commands.  Some SCSI devices get
+    confused if they receive SCSI Commands too soon after a SCSI Bus Reset.
+    Note that a timer interrupt may occur here, but all active CCBs have
+    already been marked Reset and so a reentrant call will return Pending.
+  */
+  BusLogic_Delay(HostAdapter->BusSettleTime);
   /*
-    Perform completion processing for the Command being Reset.
+    If this is a Synchronous Reset, perform completion processing for
+    the Command being Reset.
   */
-  if (Command != NULL)
+  if (ResetFlags & SCSI_RESET_SYNCHRONOUS)
     {
       Command->result = DID_RESET << 16;
       Command->scsi_done(Command);
     }
   /*
-    Perform completion processing for any other active CCBs.
+    Perform completion processing for all CCBs marked as Reset.
   */
   for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll)
     if (CCB->Status == BusLogic_CCB_Reset)
       {
 	Command = CCB->Command;
 	BusLogic_DeallocateCCB(CCB);
-	if (Command != NULL)
+	while (Command != NULL)
 	  {
+	    SCSI_Command_T *NextCommand = Command->reset_chain;
+	    Command->reset_chain = NULL;
 	    Command->result = DID_RESET << 16;
 	    Command->scsi_done(Command);
+	    Command = NextCommand;
 	  }
       }
-  return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+  for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+    HostAdapter->LastResetTime[TargetID] = jiffies;
+  Result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+  /*
+    Release exclusive access to Host Adapter.
+  */
+Done:
+  BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+  return Result;
 }
 
 
 /*
-  BusLogic_BusDeviceReset sends a Bus Device Reset to the Target
-  associated with Command.
+  BusLogic_SendBusDeviceReset sends a Bus Device Reset to the Target
+  Device associated with Command.
 */
 
-static int BusLogic_BusDeviceReset(BusLogic_HostAdapter_T *HostAdapter,
-				   SCSI_Command_T *Command)
+static int BusLogic_SendBusDeviceReset(BusLogic_HostAdapter_T *HostAdapter,
+				       SCSI_Command_T *Command,
+				       unsigned int ResetFlags)
 {
-  BusLogic_CCB_T *CCB = BusLogic_AllocateCCB(HostAdapter), *XCCB;
   unsigned char TargetID = Command->target;
+  BusLogic_Lock_T Lock;
+  BusLogic_CCB_T *CCB;
+  int Result = -1;
   /*
-    If sending a Bus Device Reset is impossible, attempt a full Host
-    Adapter Hard Reset and SCSI Bus Reset.
+    Acquire exclusive access to Host Adapter.
   */
-  if (CCB == NULL)
-    return BusLogic_ResetHostAdapter(HostAdapter, Command);
+  BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+  /*
+    If this is an Asynchronous Reset and this Command has already completed,
+    then no Reset is necessary.
+  */
+  if (ResetFlags & SCSI_RESET_ASYNCHRONOUS)
+    {
+      if (Command->serial_number != Command->serial_number_at_timeout)
+	{
+	  printk("scsi%d: Unable to Reset Command to Target %d - "
+		 "Already Completed\n", HostAdapter->HostNumber, TargetID);
+	  Result = SCSI_RESET_NOT_RUNNING;
+	  goto Done;
+	}
+      for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll)
+	if (CCB->Command == Command) break;
+      if (CCB == NULL)
+	{
+	  printk("scsi%d: Unable to Reset Command to Target %d - "
+		 "No CCB Found\n", HostAdapter->HostNumber, TargetID);
+	  Result = SCSI_RESET_NOT_RUNNING;
+	  goto Done;
+	}
+      else if (CCB->Status == BusLogic_CCB_Completed)
+	{
+	  printk("scsi%d: Unable to Reset Command to Target %d - "
+		 "CCB Completed\n", HostAdapter->HostNumber, TargetID);
+	  Result = SCSI_RESET_NOT_RUNNING;
+	  goto Done;
+	}
+      else if (CCB->Status == BusLogic_CCB_Reset)
+	{
+	  printk("scsi%d: Unable to Reset Command to Target %d - "
+		 "Reset Pending\n", HostAdapter->HostNumber, TargetID);
+	  Result = SCSI_RESET_PENDING;
+	  goto Done;
+	}
+    }
+  /*
+    If this is a Synchronous Reset and a Bus Device Reset is already pending
+    for this Target Device, do not send a second one.  Add this Command to
+    the list of Commands for which completion processing must be performed
+    when the Bus Device Reset CCB completes.
+  */
+  if (ResetFlags & SCSI_RESET_SYNCHRONOUS)
+    if ((CCB = HostAdapter->BusDeviceResetPendingCCB[TargetID]) != NULL)
+      {
+	Command->reset_chain = CCB->Command;
+	CCB->Command = Command;
+	Result = SCSI_RESET_PENDING;
+	goto Done;
+      }
+  /*
+    Firmware versions prior to 5.xx treat a Bus Device Reset as a non-tagged
+    command.  Since non-tagged commands are not sent by the Host Adapter until
+    the queue of outstanding tagged commands has completed, it is effectively
+    impossible to send a Bus Device Reset while there are tagged commands
+    outstanding.  Therefore, in that case a full Host Adapter Hard Reset and
+    SCSI Bus Reset must be done.
+  */
+  if (HostAdapter->TaggedQueuingActive[TargetID] &&
+      HostAdapter->ActiveCommandCount[TargetID] > 0 &&
+      HostAdapter->FirmwareVersion[0] < '5')
+    goto Done;
+  /*
+    Allocate a CCB from the Host Adapter's free list.  In the unlikely event
+    that there are none available and memory allocation fails, attempt a full
+    Host Adapter Hard Reset and SCSI Bus Reset.
+  */
+  CCB = BusLogic_AllocateCCB(HostAdapter);
+  if (CCB == NULL) goto Done;
   printk("scsi%d: Sending Bus Device Reset CCB #%d to Target %d\n",
 	 HostAdapter->HostNumber, CCB->SerialNumber, TargetID);
-  CCB->Opcode = BusLogic_SCSIBusDeviceReset;
+  CCB->Opcode = BusLogic_BusDeviceReset;
   CCB->TargetID = TargetID;
-  CCB->Command = Command;
   /*
-    If there is a currently executing CCB in the Host Adapter for this Command,
-    then an Incoming Mailbox entry will be made with a completion code of
-    BusLogic_HostAdapterAssertedBusDeviceReset.  Otherwise, the CCB's Command
-    field will be left pointing to the Command so that the interrupt for the
-    completion of the Bus Device Reset can call the Completion Routine for the
-    Command.
-  */
-  BusLogic_LockHostAdapter(HostAdapter);
-  for (XCCB = HostAdapter->All_CCBs; XCCB != NULL; XCCB = XCCB->NextAll)
-    if (XCCB->Command == Command && XCCB->Status == BusLogic_CCB_Active)
-      {
-	CCB->Command = NULL;
-	/*
-	  Disable Tagged Queuing if it was active for this Target Device.
-	*/
-	if (((HostAdapter->HostWideSCSI && XCCB->WideModeTagEnable) ||
-	    (!HostAdapter->HostWideSCSI && XCCB->TagEnable)) &&
-	    (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)))
-	  {
-	    HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID);
-	    printk("scsi%d: Tagged Queuing now disabled for Target %d\n",
-		   HostAdapter->HostNumber, TargetID);
-	  }
-	break;
-      }
-  BusLogic_UnlockHostAdapter(HostAdapter);
+    For Synchronous Resets, arrange for the interrupt handler to perform
+    completion processing for the Command being Reset.
+  */
+  if (ResetFlags & SCSI_RESET_SYNCHRONOUS)
+    {
+      Command->reset_chain = NULL;
+      CCB->Command = Command;
+    }
   /*
     Attempt to write an Outgoing Mailbox with the Bus Device Reset CCB.
     If sending a Bus Device Reset is impossible, attempt a full Host
@@ -2413,11 +2909,42 @@
       printk("scsi%d: cannot write Outgoing Mailbox for Bus Device Reset\n",
 	     HostAdapter->HostNumber);
       BusLogic_DeallocateCCB(CCB);
-      return BusLogic_ResetHostAdapter(HostAdapter, Command);
+      goto Done;
     }
-  HostAdapter->ReadWriteOperationCount[TargetID] = 0;
-  HostAdapter->QueuedOperationCount[TargetID] = 0;
-  return SCSI_RESET_PENDING;
+  /*
+    If there is a currently executing CCB in the Host Adapter for this Command
+    (i.e. this is an Asynchronous Reset), then an Incoming Mailbox entry may be
+    made with a completion code of BusLogic_HostAdapterAssertedBusDeviceReset.
+    If there is no active CCB for this Command (i.e. this is a Synchronous
+    Reset), then the Bus Device Reset CCB's Command field will have been set
+    to the Command so that the interrupt for the completion of the Bus Device
+    Reset can call the Completion Routine for the Command.  On successful
+    execution of a Bus Device Reset, older firmware versions did return the
+    pending CCBs with the appropriate completion code, but more recent firmware
+    versions only return the Bus Device Reset CCB itself.  This driver handles
+    both cases by marking all the currently executing CCBs to this Target
+    Device as Reset.  When the Bus Device Reset CCB is processed by the
+    interrupt handler, any remaining CCBs marked as Reset will have completion
+    processing performed.
+  */
+  HostAdapter->BusDeviceResetPendingCCB[TargetID] = CCB;
+  HostAdapter->LastResetTime[TargetID] = jiffies;
+  for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll)
+    if (CCB->Status == BusLogic_CCB_Active && CCB->TargetID == TargetID)
+      CCB->Status = BusLogic_CCB_Reset;
+  Result = SCSI_RESET_PENDING;
+  /*
+    If a Bus Device Reset was not possible for some reason, force a full
+    Host Adapter Hard Reset and SCSI Bus Reset.
+  */
+Done:
+  if (Result < 0)
+    Result = BusLogic_ResetHostAdapter(HostAdapter, Command, ResetFlags);
+  /*
+    Release exclusive access to Host Adapter.
+  */
+  BusLogic_ReleaseHostAdapterLock(HostAdapter, &Lock);
+  return Result;
 }
 
 
@@ -2425,28 +2952,50 @@
   BusLogic_ResetCommand takes appropriate action to reset Command.
 */
 
-int BusLogic_ResetCommand(SCSI_Command_T *Command)
+int BusLogic_ResetCommand(SCSI_Command_T *Command, unsigned int ResetFlags)
 {
   BusLogic_HostAdapter_T *HostAdapter =
     (BusLogic_HostAdapter_T *) Command->host->hostdata;
   unsigned char TargetID = Command->target;
-  unsigned char ErrorRecoveryOption =
-    HostAdapter->ErrorRecoveryOption[TargetID];
-  if (ErrorRecoveryOption == BusLogic_ErrorRecoveryDefault)
-    if (Command->host->suggest_bus_reset)
-      ErrorRecoveryOption = BusLogic_ErrorRecoveryHardReset;
-    else ErrorRecoveryOption = BusLogic_ErrorRecoveryBusDeviceReset;
-  switch (ErrorRecoveryOption)
-    {
-    case BusLogic_ErrorRecoveryHardReset:
-      return BusLogic_ResetHostAdapter(HostAdapter, Command);
-    case BusLogic_ErrorRecoveryBusDeviceReset:
-      if (HostAdapter->CommandSuccessfulFlag[TargetID])
+  unsigned char ErrorRecoveryStrategy =
+    HostAdapter->ErrorRecoveryStrategy[TargetID];
+  /*
+    Disable Tagged Queuing if it is active for this Target Device and if
+    it has been less than 10 minutes since the last reset occurred, or since
+    the system was initialized if no prior resets have occurred.
+  */
+  if (HostAdapter->TaggedQueuingActive[TargetID] &&
+      jiffies - HostAdapter->LastResetTime[TargetID] < 10*60*HZ)
+    {
+      HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID);
+      HostAdapter->TaggedQueuingActive[TargetID] = false;
+      printk("scsi%d: Tagged Queuing now disabled for Target %d\n",
+	     HostAdapter->HostNumber, TargetID);
+    }
+  if (ErrorRecoveryStrategy == BusLogic_ErrorRecovery_Default)
+    if (ResetFlags & SCSI_RESET_SUGGEST_BUS_RESET)
+      ErrorRecoveryStrategy = BusLogic_ErrorRecovery_HardReset;
+    else ErrorRecoveryStrategy = BusLogic_ErrorRecovery_BusDeviceReset;
+  switch (ErrorRecoveryStrategy)
+    {
+    case BusLogic_ErrorRecovery_HardReset:
+      return BusLogic_ResetHostAdapter(HostAdapter, Command, ResetFlags);
+    case BusLogic_ErrorRecovery_BusDeviceReset:
+      /*
+	The Bus Device Reset Error Recovery Strategy only graduates to a Hard
+	Reset when no commands have completed successfully since the last Bus
+	Device Reset and it has been at least 100 milliseconds.  This prevents
+	a sequence of commands that all timeout together from immediately
+	forcing a Hard Reset before the Bus Device Reset has had a chance to
+	clear the error condition.
+      */
+      if (HostAdapter->CommandSuccessfulFlag[TargetID] ||
+	  jiffies - HostAdapter->LastResetTime[TargetID] < HZ/10)
 	{
 	  HostAdapter->CommandSuccessfulFlag[TargetID] = false;
-	  return BusLogic_BusDeviceReset(HostAdapter, Command);
+	  return BusLogic_SendBusDeviceReset(HostAdapter, Command, ResetFlags);
 	}
-      else return BusLogic_ResetHostAdapter(HostAdapter, Command);
+      else return BusLogic_ResetHostAdapter(HostAdapter, Command, ResetFlags);
     }
   printk("scsi%d: Error Recovery for Target %d Suppressed\n",
 	 HostAdapter->HostNumber, TargetID);
@@ -2456,19 +3005,18 @@
 
 /*
   BusLogic_BIOSDiskParameters returns the Heads/Sectors/Cylinders BIOS Disk
-  Parameters for Disk.  The default disk geometry is 64 heads, 32 sectors, and
-  the appropriate number of cylinders so as not to exceed drive capacity.  In
-  order for disks equal to or larger than 1 GB to be addressable by the BIOS
-  without exceeding the BIOS limitation of 1024 cylinders, Extended Translation
-  may be enabled in AutoSCSI on "C" Series boards or by a dip switch setting
-  on older boards.  With Extended Translation enabled, drives between 1 GB
-  inclusive and 2 GB exclusive are given a disk geometry of 128 heads and 32
-  sectors, and drives between 2 GB inclusive and 8 GB exclusive are given a
-  disk geometry of 255 heads and 63 sectors.  On "C" Series boards the firmware
-  can be queried for the precise translation in effect for each drive
-  individually, but there is really no need to do so since we know the total
-  capacity of the drive and whether Extended Translation is enabled, hence we
-  can deduce the BIOS disk geometry that must be in effect.
+  Parameters for Disk.  The default disk geometry is 64 heads, 32 sectors,
+  and the appropriate number of cylinders so as not to exceed drive capacity.
+  In order for disks equal to or larger than 1 GB to be addressable by the
+  BIOS without exceeding the BIOS limitation of 1024 cylinders, Extended
+  Translation may be enabled in AutoSCSI on "W" and "C" Series boards or by a
+  dip switch setting on older boards.  With Extended Translation enabled,
+  drives between 1 GB inclusive and 2 GB exclusive are given a disk geometry
+  of 128 heads and 32 sectors, and drives above 2 GB inclusive are given a
+  disk geometry of 255 heads and 63 sectors.  However, if the BIOS detects
+  that the Extended Translation setting does not match the geometry in the
+  partition table, then the translation inferred from the partition table
+  will be used by the BIOS, and a warning may be displayed.
 */
 
 int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, KernelDevice_T Device,
@@ -2477,6 +3025,7 @@
   BusLogic_HostAdapter_T *HostAdapter =
     (BusLogic_HostAdapter_T *) Disk->device->host->hostdata;
   BIOS_DiskParameters_T *DiskParameters = (BIOS_DiskParameters_T *) Parameters;
+  struct buffer_head *BufferHead;
   if (HostAdapter->ExtendedTranslation &&
       Disk->capacity >= 2*1024*1024 /* 1 GB in 512 byte sectors */)
     if (Disk->capacity >= 4*1024*1024 /* 2 GB in 512 byte sectors */)
@@ -2496,6 +3045,54 @@
     }
   DiskParameters->Cylinders =
     Disk->capacity / (DiskParameters->Heads * DiskParameters->Sectors);
+  /*
+    Attempt to read the first 1024 bytes from the disk device.
+  */
+  BufferHead = bread(MKDEV(MAJOR(Device), MINOR(Device) & ~0x0F), 0, 1024);
+  if (BufferHead == NULL) return 0;
+  /*
+    If the boot sector partition table flag is valid, search for a partition
+    table entry whose end_head matches one of the standard BusLogic geometry
+    translations (64/32, 128/32, or 255/63).
+  */
+  if (*(unsigned short *) (BufferHead->b_data + 0x1FE) == 0xAA55)
+    {
+      struct partition *PartitionEntry =
+	(struct partition *) (BufferHead->b_data + 0x1BE);
+      int SavedCylinders = DiskParameters->Cylinders, PartitionNumber;
+      for (PartitionNumber = 0; PartitionNumber < 4; PartitionNumber++)
+	{
+	  if (PartitionEntry->end_head == 64-1)
+	    {
+	      DiskParameters->Heads = 64;
+	      DiskParameters->Sectors = 32;
+	      break;
+	    }
+	  else if (PartitionEntry->end_head == 128-1)
+	    {
+	      DiskParameters->Heads = 128;
+	      DiskParameters->Sectors = 32;
+	      break;
+	    }
+	  else if (PartitionEntry->end_head == 255-1)
+	    {
+	      DiskParameters->Heads = 255;
+	      DiskParameters->Sectors = 63;
+	      break;
+	    }
+	  PartitionEntry++;
+	}
+      DiskParameters->Cylinders =
+	Disk->capacity / (DiskParameters->Heads * DiskParameters->Sectors);
+      if (SavedCylinders != DiskParameters->Cylinders)
+	printk("scsi%d: Warning: Extended Translation Setting "
+	       "(> 1GB Switch) does not match\n"
+	       "scsi%d: Partition Table - Adopting %d/%d Geometry "
+	       "from Partition Table\n",
+	       HostAdapter->HostNumber, HostAdapter->HostNumber,
+	       DiskParameters->Heads, DiskParameters->Sectors);
+    }
+  brelse(BufferHead);
   return 0;
 }
 
@@ -2503,7 +3100,7 @@
 /*
   BusLogic_Setup handles processing of Kernel Command Line Arguments.
 
-  For the BusLogic driver, a kernel command line entry comprises the driver
+  For the BusLogic driver, a Kernel command line entry comprises the driver
   identifier "BusLogic=" optionally followed by a comma-separated sequence of
   integers and then optionally followed by a comma-separated sequence of
   strings.  Each command line entry applies to one BusLogic Host Adapter.
@@ -2516,14 +3113,20 @@
   any I/O Address parameters are provided on the command line, then the default
   probe sequence is omitted.
 
-  The second integer specified is the number of Concurrent Commands per Logical
-  Unit to allow for Target Devices on the Host Adapter.  If unspecified, it
-  defaults to 0 which means to use the value of BusLogic_Concurrency for
-  non-ISA Host Adapters, or BusLogic_Concurrency_ISA for ISA Host Adapters.
+  The second integer specified is the Tagged Queue Depth to use for Target
+  Devices that support Tagged Queuing.  The Queue Depth is the number of SCSI
+  commands that are allowed to be concurrently presented for execution.  If
+  unspecified, it defaults to 0 which means to use a value determined
+  automatically based on the Host Adapter's Total Queue Depth and the number,
+  type, speed, and capabilities of the detected Target Devices.  For Host
+  Adapters that require ISA Bounce Buffers, the Tagged Queue Depth is
+  automatically set to BusLogic_TaggedQueueDepth_BB to avoid excessive
+  preallocation of DMA Bounce Buffer memory.  Target Devices that do not
+  support Tagged Queuing use a Queue Depth of BusLogic_UntaggedQueueDepth.
 
   The third integer specified is the Bus Settle Time in seconds.  This is
   the amount of time to wait between a Host Adapter Hard Reset which initiates
-  a SCSI Bus Reset and issuing any SCSI commands.  If unspecified, it defaults
+  a SCSI Bus Reset and issuing any SCSI Commands.  If unspecified, it defaults
   to 0 which means to use the value of BusLogic_DefaultBusSettleTime.
 
   The fourth integer specified is the Local Options.  If unspecified, it
@@ -2544,8 +3147,8 @@
 
   TQ:Default		Tagged Queuing will be permitted based on the firmware
 			version of the BusLogic Host Adapter and based on
-			whether the Concurrency value allows queuing multiple
-			commands.
+			whether the Tagged Queue Depth value allows queuing
+			multiple commands.
 
   TQ:Enable		Tagged Queuing will be enabled for all Target Devices
 			on this Host Adapter overriding any limitation that
@@ -2560,19 +3163,19 @@
 			"N", and "X" characters.  "Y" enabled Tagged Queuing,
 			"N" disables Tagged Queuing, and "X" accepts the
 			default based on the firmware version.  The first
-			character refers to Target 0, the second to Target 1,
-			and so on; if the sequence of "Y", "N", and "X"
-			characters does not cover all the Target Devices,
-			unspecified characters are assumed to be "X".
+			character refers to Target Device 0, the second to
+			Target Device 1, and so on; if the sequence of "Y",
+			"N", and "X" characters does not cover all the Target
+			Devices, unspecified characters are assumed to be "X".
 
   Note that explicitly requesting Tagged Queuing may lead to problems; this
   facility is provided primarily to allow disabling Tagged Queuing on Target
   Devices that do not implement it correctly.
 
-  The Error Recovery specification begins with "ER:" and allows for explicitly
-  specifying the Error Recovery action to be performed when ResetCommand is
-  called due to a SCSI Command failing to complete successfully.  The following
-  specification options are available:
+  The Error Recovery Strategy specification begins with "ER:" and allows for
+  explicitly specifying the Error Recovery action to be performed when
+  ResetCommand is called due to a SCSI Command failing to complete
+  successfully.  The following specification options are available:
 
   ER:Default		Error Recovery will select between the Hard Reset and
 			Bus Device Reset options based on the recommendation
@@ -2598,10 +3201,10 @@
 			"H", "B", and "N" characters.  "D" selects Default, "H"
 			selects Hard Reset, "B" selects Bus Device Reset, and
 			"N" selects None.  The first character refers to Target
-			0, the second to Target 1, and so on; if the sequence
-			of "D", "H", "B", and "N" characters does not cover all
-			the Target Devices, unspecified characters are assumed
-			to be "D".
+			Device 0, the second to Target Device 1, and so on; if
+			the sequence of "D", "H", "B", and "N" characters does
+			not cover all the possible Target Devices, unspecified
+			characters are assumed to be "D".
 */
 
 void BusLogic_Setup(char *Strings, int *Integers)
@@ -2611,14 +3214,14 @@
   static int ProbeListIndex = 0;
   int IntegerCount = Integers[0], TargetID, i;
   CommandLineEntry->IO_Address = 0;
-  CommandLineEntry->Concurrency = 0;
+  CommandLineEntry->TaggedQueueDepth = 0;
   CommandLineEntry->BusSettleTime = 0;
   CommandLineEntry->LocalOptions = 0;
   CommandLineEntry->TaggedQueuingPermitted = 0;
   CommandLineEntry->TaggedQueuingPermittedMask = 0;
-  memset(CommandLineEntry->ErrorRecoveryOption,
-	 BusLogic_ErrorRecoveryDefault,
-	 sizeof(CommandLineEntry->ErrorRecoveryOption));
+  memset(CommandLineEntry->ErrorRecoveryStrategy,
+	 BusLogic_ErrorRecovery_Default,
+	 sizeof(CommandLineEntry->ErrorRecoveryStrategy));
   if (IntegerCount > 5)
     printk("BusLogic: Unexpected Command Line Integers ignored\n");
   if (IntegerCount >= 1)
@@ -2640,7 +3243,7 @@
 		       "(duplicate I/O Address 0x%X)\n", IO_Address);
 		return;
 	      }
-	    else if (IO_Address >= 0x1000 ||
+	    else if (IO_Address >= 0x400 ||
 		     IO_Address == BusLogic_IO_StandardAddresses[i]) break;
 	  BusLogic_IO_AddressProbeList[ProbeListIndex++] = IO_Address;
 	  BusLogic_IO_AddressProbeList[ProbeListIndex] = 0;
@@ -2649,14 +3252,14 @@
     }
   if (IntegerCount >= 2)
     {
-      unsigned short Concurrency = Integers[2];
-      if (Concurrency > BusLogic_MailboxCount)
+      unsigned short TaggedQueueDepth = Integers[2];
+      if (TaggedQueueDepth > BusLogic_MaxTaggedQueueDepth)
 	{
 	  printk("BusLogic: Invalid Command Line Entry "
-		 "(illegal Concurrency %d)\n", Concurrency);
+		 "(illegal Tagged Queue Depth %d)\n", TaggedQueueDepth);
 	  return;
 	}
-      CommandLineEntry->Concurrency = Concurrency;
+      CommandLineEntry->TaggedQueueDepth = TaggedQueueDepth;
     }
   if (IntegerCount >= 3)
     CommandLineEntry->BusSettleTime = Integers[3];
@@ -2690,7 +3293,7 @@
 	  CommandLineEntry->TaggedQueuingPermittedMask = 0xFFFF;
 	}
       else
-	for (TargetID = 0; TargetID < BusLogic_MaxTargetIDs; TargetID++)
+	for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
 	  switch (*Strings++)
 	    {
 	    case 'Y':
@@ -2704,7 +3307,7 @@
 	      break;
 	    default:
 	      Strings--;
-	      TargetID = BusLogic_MaxTargetIDs;
+	      TargetID = BusLogic_MaxTargetDevices;
 	      break;
 	    }
     }
@@ -2717,47 +3320,47 @@
       else if (strncmp(Strings, "HardReset", 9) == 0)
 	{
 	  Strings += 9;
-	  memset(CommandLineEntry->ErrorRecoveryOption,
-		 BusLogic_ErrorRecoveryHardReset,
-		 sizeof(CommandLineEntry->ErrorRecoveryOption));
+	  memset(CommandLineEntry->ErrorRecoveryStrategy,
+		 BusLogic_ErrorRecovery_HardReset,
+		 sizeof(CommandLineEntry->ErrorRecoveryStrategy));
 	}
       else if (strncmp(Strings, "BusDeviceReset", 14) == 0)
 	{
 	  Strings += 14;
-	  memset(CommandLineEntry->ErrorRecoveryOption,
-		 BusLogic_ErrorRecoveryBusDeviceReset,
-		 sizeof(CommandLineEntry->ErrorRecoveryOption));
+	  memset(CommandLineEntry->ErrorRecoveryStrategy,
+		 BusLogic_ErrorRecovery_BusDeviceReset,
+		 sizeof(CommandLineEntry->ErrorRecoveryStrategy));
 	}
       else if (strncmp(Strings, "None", 4) == 0)
 	{
 	  Strings += 4;
-	  memset(CommandLineEntry->ErrorRecoveryOption,
-		 BusLogic_ErrorRecoveryNone,
-		 sizeof(CommandLineEntry->ErrorRecoveryOption));
+	  memset(CommandLineEntry->ErrorRecoveryStrategy,
+		 BusLogic_ErrorRecovery_None,
+		 sizeof(CommandLineEntry->ErrorRecoveryStrategy));
 	}
       else
-	for (TargetID = 0; TargetID < BusLogic_MaxTargetIDs; TargetID++)
+	for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
 	  switch (*Strings++)
 	    {
 	    case 'D':
-	      CommandLineEntry->ErrorRecoveryOption[TargetID] =
-		BusLogic_ErrorRecoveryDefault;
+	      CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
+		BusLogic_ErrorRecovery_Default;
 	      break;
 	    case 'H':
-	      CommandLineEntry->ErrorRecoveryOption[TargetID] =
-		BusLogic_ErrorRecoveryHardReset;
+	      CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
+		BusLogic_ErrorRecovery_HardReset;
 	      break;
 	    case 'B':
-	      CommandLineEntry->ErrorRecoveryOption[TargetID] =
-		BusLogic_ErrorRecoveryBusDeviceReset;
+	      CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
+		BusLogic_ErrorRecovery_BusDeviceReset;
 	      break;
 	    case 'N':
-	      CommandLineEntry->ErrorRecoveryOption[TargetID] =
-		BusLogic_ErrorRecoveryNone;
+	      CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
+		BusLogic_ErrorRecovery_None;
 	      break;
 	    default:
 	      Strings--;
-	      TargetID = BusLogic_MaxTargetIDs;
+	      TargetID = BusLogic_MaxTargetDevices;
 	      break;
 	    }
     }
@@ -2769,7 +3372,6 @@
 /*
   Include Module support if requested.
 */
-
 
 #ifdef MODULE
 
diff -u --recursive --new-file v1.3.88/linux/drivers/scsi/BusLogic.h linux/drivers/scsi/BusLogic.h
--- v1.3.88/linux/drivers/scsi/BusLogic.h	Sat Mar  9 15:41:12 1996
+++ linux/drivers/scsi/BusLogic.h	Sun Apr 14 11:21:08 1996
@@ -4,7 +4,22 @@
 
   Copyright 1995 by Leonard N. Zubkoff <lnz@dandelion.com>
 
-  See BusLogic.c for licensing information.
+  This program is free software; you may redistribute and/or modify it under
+  the terms of the GNU General Public License Version 2 as published by the
+  Free Software Foundation, provided that none of the source code or runtime
+  copyright notices are removed or modified.
+
+  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 complete details.
+
+  The author respectfully requests that any modifications to this software be
+  sent directly to him for evaluation and testing.
+
+  Special thanks to Wayne Yen and Alex Win of BusLogic, whose advice has been
+  invaluable, to David Gentzel, for writing the original Linux BusLogic driver,
+  and to Paul Gortmaker, for being such a dedicated test site.
 
 */
 
@@ -17,6 +32,7 @@
 typedef struct pt_regs Registers_T;
 typedef Scsi_Host_Template SCSI_Host_Template_T;
 typedef struct Scsi_Host SCSI_Host_T;
+typedef struct scsi_device SCSI_Device_T;
 typedef struct scsi_disk SCSI_Disk_T;
 typedef struct scsi_cmnd SCSI_Command_T;
 typedef struct scatterlist SCSI_ScatterList_T;
@@ -33,7 +49,7 @@
 int BusLogic_QueueCommand(SCSI_Command_T *,
 			  void (*CompletionRoutine)(SCSI_Command_T *));
 int BusLogic_AbortCommand(SCSI_Command_T *);
-int BusLogic_ResetCommand(SCSI_Command_T *);
+int BusLogic_ResetCommand(SCSI_Command_T *, unsigned int);
 int BusLogic_BIOSDiskParameters(SCSI_Disk_T *, KernelDevice_T, int *);
 
 
@@ -87,47 +103,30 @@
 
 
 /*
-  Define the maximum number of Target IDs supported by this driver.
+  Define the maximum number of Target Devices supported by this driver.
 */
 
-#define BusLogic_MaxTargetIDs			16
-
-
-/*
-  Define the number of Incoming and Outgoing Mailboxes used by this driver.
-  The maximum possible value is 255, since the MailboxCount parameter to the
-  Initialize Extended Mailbox command is limited to a single byte.
-*/
-
-#define BusLogic_MailboxCount			64
-
-
-/*
-  Define the number of Command Control Blocks (CCBs) to create during
-  initialization for each Host Adapter.  Additional CCBs will be allocated
-  if necessary as commands are queued.
-*/
-
-#define BusLogic_InitialCCBs			32
+#define BusLogic_MaxTargetDevices		16
 
 
 /*
   Define the maximum number of Scatter/Gather Segments used by this driver.
-  For maximum performance, it is important that this limit be at least as
-  large as the maximum single request generated by the routine make_request.
+  For optimal performance, it is important that this limit be at least as
+  large as the maximum single request generated by the I/O Subsystem.
 */
 
 #define BusLogic_ScatterGatherLimit		128
 
 
 /*
-  Define the default number of Concurrent Commands per Logical Unit to allow
-  for Target Devices depending on whether or not ISA bounce buffers are
-  required.
+  Define the maximum and default Queue Depth to allow for Target Devices
+  depending on whether or not they support Tagged Queuing and whether or not
+  ISA Bounce Buffers are required.
 */
 
-#define BusLogic_Concurrency			7
-#define BusLogic_Concurrency_BB			1
+#define BusLogic_MaxTaggedQueueDepth		31
+#define BusLogic_TaggedQueueDepth_BB		2
+#define BusLogic_UntaggedQueueDepth		3
 
 
 /*
@@ -155,21 +154,22 @@
 #define BusLogic_TraceHardReset			2
 #define BusLogic_TraceConfiguration		4
 #define BusLogic_TraceErrors			8
+#define BusLogic_TraceQueueDepths		16
 
 
 /*
-  Define the possible Error Recovery Options.
+  Define the possible Error Recovery Strategy Options.
 */
 
-#define BusLogic_ErrorRecoveryDefault		0
-#define BusLogic_ErrorRecoveryHardReset		1
-#define BusLogic_ErrorRecoveryBusDeviceReset	2
-#define BusLogic_ErrorRecoveryNone		3
+#define BusLogic_ErrorRecovery_Default		0
+#define BusLogic_ErrorRecovery_HardReset	1
+#define BusLogic_ErrorRecovery_BusDeviceReset	2
+#define BusLogic_ErrorRecovery_None		3
 
 static char
-  *BusLogic_ErrorRecoveryOptions[] =
+  *BusLogic_ErrorRecoveryStrategyNames[] =
     { "Default", "Hard Reset", "Bus Device Reset", "None" },
-  *BusLogic_ErrorRecoveryOptions2[] =
+  *BusLogic_ErrorRecoveryStrategyLetters[] =
     { "D", "H", "B", "N" };
 
 
@@ -250,10 +250,10 @@
 {
   BusLogic_TestCommandCompleteInterrupt =	0x00,	/* documented */
   BusLogic_InitializeMailbox =			0x01,	/* documented */
-  BusLogic_StartMailboxCommand =		0x02,	/* documented */
-  BusLogic_StartBIOSCommand =			0x03,	/* documented */
+  BusLogic_ExecuteMailboxCommand =		0x02,	/* documented */
+  BusLogic_ExecuteBIOSCommand =			0x03,	/* documented */
   BusLogic_InquireBoardID =			0x04,	/* documented */
-  BusLogic_EnableOutgoingMailboxAvailableIRQ =	0x05,	/* documented */
+  BusLogic_EnableOutgoingMailboxAvailableInt =	0x05,	/* documented */
   BusLogic_SetSCSISelectionTimeout =		0x06,	/* documented */
   BusLogic_SetPreemptTimeOnBus =		0x07,	/* documented */
   BusLogic_SetTimeOffBus =			0x08,	/* ISA Bus only */
@@ -270,13 +270,16 @@
   BusLogic_HostAdapterDiagnostic =		0x20,	/* documented */
   BusLogic_SetAdapterOptions =			0x21,	/* documented */
   BusLogic_InquireInstalledDevicesID8to15 =	0x23,	/* Wide only */
+  BusLogic_InquireDevices =			0x24,	/* "W" and "C" only */
   BusLogic_InitializeExtendedMailbox =		0x81,	/* documented */
   BusLogic_InquireFirmwareVersion3rdDigit =	0x84,	/* undocumented */
   BusLogic_InquireFirmwareVersionLetter =	0x85,	/* undocumented */
+  BusLogic_InquireGenericIOPortInformation =	0x86,	/* PCI only */
   BusLogic_InquireBoardModelNumber	 =	0x8B,	/* undocumented */
   BusLogic_InquireSynchronousPeriod =		0x8C,	/* undocumented */
   BusLogic_InquireExtendedSetupInformation =	0x8D,	/* documented */
   BusLogic_EnableStrictRoundRobinMode =		0x8F,	/* documented */
+  BusLogic_FetchHostAdapterLocalRAM =		0x91,	/* undocumented */
   BusLogic_ModifyIOAddress =			0x95,	/* PCI only */
   BusLogic_EnableWideModeCCB =			0x96	/* Wide only */
 }
@@ -289,24 +292,32 @@
 
 typedef struct BusLogic_BoardID
 {
-  unsigned char BoardType;
-  unsigned char CustomFeatures;
-  unsigned char FirmwareVersion1stDigit;
-  unsigned char FirmwareVersion2ndDigit;
+  unsigned char BoardType;				/* Byte 0 */
+  unsigned char CustomFeatures;				/* Byte 1 */
+  unsigned char FirmwareVersion1stDigit;		/* Byte 2 */
+  unsigned char FirmwareVersion2ndDigit;		/* Byte 3 */
 }
 BusLogic_BoardID_T;
 
 
 /*
   Define the Inquire Installed Devices ID 0 to 7 and Inquire Installed
-  Devices ID 8 to 15 reply type.  For each Target ID, a byte is returned
+  Devices ID 8 to 15 reply type.  For each Target Device, a byte is returned
   where bit 0 set indicates that Logical Unit 0 exists, bit 1 set indicates
   that Logical Unit 1 exists, and so on.
 */
 
 typedef unsigned char BusLogic_InstalledDevices8_T[8];
 
-typedef unsigned char BusLogic_InstalledDevices_T[BusLogic_MaxTargetIDs];
+
+/*
+  Define the Inquire Devices reply type.  Inquire Devices only tests Logical
+  Unit 0 of each Target Device unlike Inquire Installed Devices which tests
+  Logical Units 0 - 7.  Two bytes are returned, where bit 0 set indicates
+  that Target Device 0 exists, and so on.
+*/
+
+typedef unsigned short BusLogic_InstalledDevices_T;
 
 
 /*
@@ -315,20 +326,20 @@
 
 typedef struct BusLogic_Configuration
 {
-  unsigned char :5;				/* Byte 0: DMA Channel */
-  boolean DMA_Channel5:1;
-  boolean DMA_Channel6:1;
-  boolean DMA_Channel7:1;
-  boolean IRQ_Channel9:1;			/* Byte 1: IRQ Channel */
-  boolean IRQ_Channel10:1;
-  boolean IRQ_Channel11:1;
-  boolean IRQ_Channel12:1;
-  unsigned char :1;
-  boolean IRQ_Channel14:1;
-  boolean IRQ_Channel15:1;
-  unsigned char :1;
-  unsigned char HostAdapterID:4;		/* Byte 2: Host Adapter ID */
-  unsigned char :4;
+  unsigned char :5;					/* Byte 0 Bits 0-4 */
+  boolean DMA_Channel5:1;				/* Byte 0 Bit 5 */
+  boolean DMA_Channel6:1;				/* Byte 0 Bit 6 */
+  boolean DMA_Channel7:1;				/* Byte 0 Bit 7 */
+  boolean IRQ_Channel9:1;				/* Byte 1 Bit 0 */
+  boolean IRQ_Channel10:1;				/* Byte 1 Bit 1 */
+  boolean IRQ_Channel11:1;				/* Byte 1 Bit 2 */
+  boolean IRQ_Channel12:1;				/* Byte 1 Bit 3 */
+  unsigned char :1;					/* Byte 1 Bit 4 */
+  boolean IRQ_Channel14:1;				/* Byte 1 Bit 5 */
+  boolean IRQ_Channel15:1;				/* Byte 1 Bit 6 */
+  unsigned char :1;					/* Byte 1 Bit 7 */
+  unsigned char HostAdapterID:4;			/* Byte 2 Bits 0-3 */
+  unsigned char :4;					/* Byte 2 Bits 4-7 */
 }
 BusLogic_Configuration_T;
 
@@ -339,9 +350,9 @@
 
 typedef struct BusLogic_SynchronousValue
 {
-  unsigned char Offset:4;
-  unsigned char TransferPeriod:3;
-  boolean Synchronous:1;
+  unsigned char Offset:4;				/* Bits 0-3 */
+  unsigned char TransferPeriod:3;			/* Bits 4-6 */
+  boolean Synchronous:1;				/* Bit 7 */
 }
 BusLogic_SynchronousValue_T;
 
@@ -349,27 +360,27 @@
   BusLogic_SynchronousValues8_T[8];
 
 typedef BusLogic_SynchronousValue_T
-  BusLogic_SynchronousValues_T[BusLogic_MaxTargetIDs];
+  BusLogic_SynchronousValues_T[BusLogic_MaxTargetDevices];
 
 typedef struct BusLogic_SetupInformation
 {
-  boolean SynchronousInitiationEnabled:1;	/* Byte 0 */
-  boolean ParityCheckEnabled:1;
-  unsigned char :6;
-  unsigned char BusTransferRate;		/* Byte 1 */
-  unsigned char PreemptTimeOnBus;		/* Byte 2 */
-  unsigned char TimeOffBus;			/* Byte 3 */
-  unsigned char MailboxCount;			/* Byte 4 */
-  unsigned char MailboxAddress[3];		/* Bytes 5-7 */
+  boolean SynchronousInitiationEnabled:1;		/* Byte 0 Bit 0 */
+  boolean ParityCheckEnabled:1;				/* Byte 0 Bit 1 */
+  unsigned char :6;					/* Byte 0 Bits 2-7 */
+  unsigned char BusTransferRate;			/* Byte 1 */
+  unsigned char PreemptTimeOnBus;			/* Byte 2 */
+  unsigned char TimeOffBus;				/* Byte 3 */
+  unsigned char MailboxCount;				/* Byte 4 */
+  unsigned char MailboxAddress[3];			/* Bytes 5-7 */
   BusLogic_SynchronousValues8_T SynchronousValuesID0to7; /* Bytes 8-15 */
-  unsigned char DisconnectPermittedID0to7;	/* Byte 16 */
-  unsigned char Signature;			/* Byte 17 */
-  unsigned char CharacterD;			/* Byte 18 */
-  unsigned char BusLetter;			/* Byte 19 */
-  unsigned char :8;				/* Byte 20 */
-  unsigned char :8;				/* Byte 21 */
+  unsigned char DisconnectPermittedID0to7;		/* Byte 16 */
+  unsigned char Signature;				/* Byte 17 */
+  unsigned char CharacterD;				/* Byte 18 */
+  unsigned char BusLetter;				/* Byte 19 */
+  unsigned char :8;					/* Byte 20 */
+  unsigned char :8;					/* Byte 21 */
   BusLogic_SynchronousValues8_T SynchronousValuesID8to15; /* Bytes 22-29 */
-  unsigned char DisconnectPermittedID8to15;	/* Byte 30 */
+  unsigned char DisconnectPermittedID8to15;		/* Byte 30 */
 }
 BusLogic_SetupInformation_T;
 
@@ -380,8 +391,8 @@
 
 typedef struct BusLogic_ExtendedMailboxRequest
 {
-  unsigned char MailboxCount;
-  void *BaseMailboxAddress __attribute__ ((packed));
+  unsigned char MailboxCount;				/* Byte 0 */
+  void *BaseMailboxAddress __attribute__ ((packed));	/* Bytes 1-4 */
 }
 BusLogic_ExtendedMailboxRequest_T;
 
@@ -401,6 +412,26 @@
 
 
 /*
+  Define the Inquire Generic I/O Port Information reply type.
+*/
+
+typedef struct BusLogic_GenericIOPortInformation
+{
+  unsigned char ISACompatibleIOPort;			/* Byte 0 */
+  unsigned char PCIAssignedIRQChannel;			/* Byte 1 */
+  boolean LowByteTerminated:1;				/* Byte 2 Bit 0 */
+  boolean HighByteTerminated:1;				/* Byte 2 Bit 1 */
+  unsigned char :2;					/* Byte 2 Bits 2-3 */
+  boolean JP1:1;					/* Byte 2 Bit 4 */
+  boolean JP2:1;					/* Byte 2 Bit 5 */
+  boolean JP3:1;					/* Byte 2 Bit 6 */
+  boolean Valid:1;					/* Byte 2 Bit 7 */
+  unsigned char :8;					/* Byte 3 */
+}
+BusLogic_GenericIOPortInformation_T;
+
+
+/*
   Define the Inquire Board Model Number reply type.
 */
 
@@ -408,12 +439,12 @@
 
 
 /*
-  Define the Inquire Synchronous Period reply type.  For each Target ID, a byte
-  is returned which represents the Synchronous Transfer Period in units of 10
-  nanoseconds.
+  Define the Inquire Synchronous Period reply type.  For each Target Device,
+  a byte is returned which represents the Synchronous Transfer Period in units
+  of 10 nanoseconds.
 */
 
-typedef unsigned char BusLogic_SynchronousPeriod_T[BusLogic_MaxTargetIDs];
+typedef unsigned char BusLogic_SynchronousPeriod_T[BusLogic_MaxTargetDevices];
 
 
 /*
@@ -427,13 +458,15 @@
   unsigned short ScatterGatherLimit;			/* Bytes 2-3 */
   unsigned char MailboxCount;				/* Byte 4 */
   void *BaseMailboxAddress __attribute__ ((packed));	/* Bytes 5-8 */
-  struct { unsigned char :6;				/* Byte 9 */
-	   boolean LevelSensitiveInterrupts:1;
-	   unsigned char :1; } Misc;
+  struct { unsigned char :6;				/* Byte 9 Bits 0-5 */
+	   boolean LevelSensitiveInterrupts:1;		/* Byte 9 Bit 6 */
+	   unsigned char :1; } Misc;			/* Byte 9 Bit 7 */
   unsigned char FirmwareRevision[3];			/* Bytes 10-12 */
   boolean HostWideSCSI:1;				/* Byte 13 Bit 0 */
   boolean HostDifferentialSCSI:1;			/* Byte 13 Bit 1 */
-  unsigned char :6;
+  boolean HostAutomaticConfiguration:1;			/* Byte 13 Bit 2 */
+  boolean HostUltraSCSI:1;				/* Byte 13 Bit 3 */
+  unsigned char :4;					/* Byte 13 Bits 4-7 */
 }
 BusLogic_ExtendedSetupInformation_T;
 
@@ -449,6 +482,47 @@
 
 
 /*
+  Define the Fetch Host Adapter Local RAM request type.
+*/
+
+#define BusLogic_BIOS_BaseOffset		0
+#define BusLogic_AutoSCSI_BaseOffset		64
+
+typedef struct BusLogic_FetchHostAdapterLocalRAMRequest
+{
+  unsigned char ByteOffset;				/* Byte 0 */
+  unsigned char ByteCount;				/* Byte 1 */
+}
+BusLogic_FetchHostAdapterLocalRAMRequest_T;
+
+
+/*
+  Define the Host Adapter Local RAM Auto SCSI Byte 15 reply structure.
+*/
+
+typedef struct BusLogic_AutoSCSIByte15
+{
+  unsigned char LowByteTerminated:1;			/* Bit 0 */
+  unsigned char :1;					/* Bit 1 */
+  unsigned char HighByteTerminated:1;			/* Bit 2 */
+  unsigned char :5;					/* Bits 3-7 */
+}
+BusLogic_AutoSCSIByte15_T;
+
+
+/*
+  Define the Host Adapter Local RAM Auto SCSI Byte 45 reply structure.
+*/
+
+typedef struct BusLogic_AutoSCSIByte45
+{
+  unsigned char ForceBusDeviceScanningOrder:1;		/* Bit 0 */
+  unsigned char :7;					/* Bits 1-7 */
+}
+BusLogic_AutoSCSIByte45_T;
+
+
+/*
   Define the Modify I/O Address request type.  On PCI Host Adapters, the
   Modify I/O Address command allows modification of the ISA compatible I/O
   Address that the Host Adapter responds to; it does not affect the PCI
@@ -469,7 +543,7 @@
 
 /*
   Define the Enable Wide Mode SCSI CCB request type.  Wide Mode CCBs are
-  necessary to support more than 8 Logical Units per Target.
+  necessary to support more than 8 Logical Units per Target Device.
 */
 
 #define BusLogic_NormalModeCCB			0x00
@@ -489,8 +563,9 @@
 
 /*
   Define a Lock data structure.  Until a true symmetric multiprocessing kernel
-  is available, locking is implemented as saving the processor flags and
-  disabling interrupts, and unlocking restores the saved processor flags.
+  with fine grained locking is available, acquiring the lock is implemented as
+  saving the processor flags and disabling interrupts, and releasing the lock
+  restores the saved processor flags.
 */
 
 typedef unsigned long BusLogic_Lock_T;
@@ -535,7 +610,7 @@
   BusLogic_InitiatorCCB_ScatterGather =		0x02,
   BusLogic_InitiatorCCB_ResidualDataLength =	0x03,
   BusLogic_InitiatorCCB_ScatterGatherResidual =	0x04,
-  BusLogic_SCSIBusDeviceReset =			0x81
+  BusLogic_BusDeviceReset =			0x81
 }
 BusLogic_CCB_Opcode_T;
 
@@ -640,8 +715,8 @@
 
 typedef struct BusLogic_ScatterGatherSegment
 {
-  unsigned long SegmentByteCount;
-  void *SegmentDataPointer;
+  unsigned long SegmentByteCount;			/* Bytes 0-3 */
+  void *SegmentDataPointer;				/* Bytes 4-7 */
 }
 BusLogic_ScatterGatherSegment_T;
 
@@ -710,9 +785,9 @@
 
 typedef struct BusLogic_OutgoingMailbox
 {
-  BusLogic_CCB_T *CCB;
-  unsigned long :24;
-  BusLogic_ActionCode_T ActionCode:8;
+  BusLogic_CCB_T *CCB;					/* Bytes 0-3 */
+  unsigned long :24;					/* Byte 4 */
+  BusLogic_ActionCode_T ActionCode:8;			/* Bytes 5-7 */
 }
 BusLogic_OutgoingMailbox_T;
 
@@ -723,11 +798,11 @@
 
 typedef struct BusLogic_IncomingMailbox
 {
-  BusLogic_CCB_T *CCB;
-  BusLogic_HostAdapterStatus_T HostAdapterStatus:8;
-  BusLogic_TargetDeviceStatus_T TargetDeviceStatus:8;
-  unsigned char :8;
-  BusLogic_CompletionCode_T CompletionCode:8;
+  BusLogic_CCB_T *CCB;					/* Bytes 0-3 */
+  BusLogic_HostAdapterStatus_T HostAdapterStatus:8;	/* Byte 4 */
+  BusLogic_TargetDeviceStatus_T TargetDeviceStatus:8;	/* Byte 5 */
+  unsigned char :8;					/* Byte 6 */
+  BusLogic_CompletionCode_T CompletionCode:8;		/* Byte 7 */
 }
 BusLogic_IncomingMailbox_T;
 
@@ -759,12 +834,12 @@
 typedef struct BusLogic_CommandLineEntry
 {
   unsigned short IO_Address;
-  unsigned short Concurrency;
+  unsigned short TaggedQueueDepth;
   unsigned short BusSettleTime;
   unsigned short LocalOptions;
   unsigned short TaggedQueuingPermitted;
   unsigned short TaggedQueuingPermittedMask;
-  unsigned char ErrorRecoveryOption[BusLogic_MaxTargetIDs];
+  unsigned char ErrorRecoveryStrategy[BusLogic_MaxTargetDevices];
 }
 BusLogic_CommandLineEntry_T;
 
@@ -794,14 +869,25 @@
   boolean LevelSensitiveInterrupts:1;
   boolean HostWideSCSI:1;
   boolean HostDifferentialSCSI:1;
-  boolean HostAdapterResetPending:1;
+  boolean HostAutomaticConfiguration:1;
+  boolean HostUltraSCSI:1;
+  boolean TerminationInfoValid:1;
+  boolean LowByteTerminated:1;
+  boolean HighByteTerminated:1;
   boolean BounceBuffersRequired:1;
+  boolean StrictRoundRobinModeSupported:1;
+  boolean HostAdapterResetRequested:1;
   volatile boolean HostAdapterCommandCompleted:1;
   unsigned short HostAdapterScatterGatherLimit;
   unsigned short DriverScatterGatherLimit;
-  unsigned short MaxTargetIDs;
+  unsigned short MaxTargetDevices;
   unsigned short MaxLogicalUnits;
-  unsigned short Concurrency;
+  unsigned short MailboxCount;
+  unsigned short InitialCCBs;
+  unsigned short IncrementalCCBs;
+  unsigned short TotalQueueDepth;
+  unsigned short TaggedQueueDepth;
+  unsigned short UntaggedQueueDepth;
   unsigned short BusSettleTime;
   unsigned short LocalOptions;
   unsigned short DisconnectPermitted;
@@ -810,30 +896,30 @@
   BusLogic_InstalledDevices_T InstalledDevices;
   BusLogic_SynchronousValues_T SynchronousValues;
   BusLogic_SynchronousPeriod_T SynchronousPeriod;
-  BusLogic_Lock_T Lock;
-  struct BusLogic_HostAdapter *Next;
   BusLogic_CommandLineEntry_T *CommandLineEntry;
+  struct BusLogic_HostAdapter *Next;
   BusLogic_CCB_T *All_CCBs;
   BusLogic_CCB_T *Free_CCBs;
-  unsigned char ErrorRecoveryOption[BusLogic_MaxTargetIDs];
-  unsigned char CommandSuccessfulFlag[BusLogic_MaxTargetIDs];
-  unsigned long ReadWriteOperationCount[BusLogic_MaxTargetIDs];
-  unsigned char QueuedOperationCount[BusLogic_MaxTargetIDs];
-  unsigned long LastSequencePoint[BusLogic_MaxTargetIDs];
+  BusLogic_CCB_T *BusDeviceResetPendingCCB[BusLogic_MaxTargetDevices];
+  unsigned char ErrorRecoveryStrategy[BusLogic_MaxTargetDevices];
+  unsigned char TaggedQueuingActive[BusLogic_MaxTargetDevices];
+  unsigned char CommandSuccessfulFlag[BusLogic_MaxTargetDevices];
+  unsigned char ActiveCommandCount[BusLogic_MaxTargetDevices];
+  unsigned long TotalCommandCount[BusLogic_MaxTargetDevices];
+  unsigned long LastSequencePoint[BusLogic_MaxTargetDevices];
+  unsigned long LastResetTime[BusLogic_MaxTargetDevices];
   BusLogic_OutgoingMailbox_T *FirstOutgoingMailbox;
   BusLogic_OutgoingMailbox_T *LastOutgoingMailbox;
   BusLogic_OutgoingMailbox_T *NextOutgoingMailbox;
   BusLogic_IncomingMailbox_T *FirstIncomingMailbox;
   BusLogic_IncomingMailbox_T *LastIncomingMailbox;
   BusLogic_IncomingMailbox_T *NextIncomingMailbox;
-  BusLogic_OutgoingMailbox_T OutgoingMailboxes[BusLogic_MailboxCount];
-  BusLogic_IncomingMailbox_T IncomingMailboxes[BusLogic_MailboxCount];
 }
 BusLogic_HostAdapter_T;
 
 
 /*
-  Define a symbolic structure for the BIOS Disk Parameters.
+  Define a structure for the BIOS Disk Parameters.
 */
 
 typedef struct BIOS_DiskParameters
@@ -846,46 +932,50 @@
 
 
 /*
-  BusLogic_LockHostAdapter acquires exclusive access to Host Adapter.
+  BusLogic_AcquireHostAdapterLock acquires exclusive access to Host Adapter.
 */
 
 static inline
-void BusLogic_LockHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
+void BusLogic_AcquireHostAdapterLock(BusLogic_HostAdapter_T *HostAdapter,
+				     BusLogic_Lock_T *Lock)
 {
-  save_flags(HostAdapter->Lock);
+  save_flags(*Lock);
   cli();
 }
 
 
 /*
-  BusLogic_UnlockHostAdapter releases exclusive access to Host Adapter.
+  BusLogic_ReleaseHostAdapterLock releases exclusive access to Host Adapter.
 */
 
 static inline
-void BusLogic_UnlockHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
+void BusLogic_ReleaseHostAdapterLock(BusLogic_HostAdapter_T *HostAdapter,
+				     BusLogic_Lock_T *Lock)
 {
-  restore_flags(HostAdapter->Lock);
+  restore_flags(*Lock);
 }
 
 
 /*
-  BusLogic_LockHostAdapterID acquires exclusive access to Host Adapter,
+  BusLogic_AcquireHostAdapterLockID acquires exclusive access to Host Adapter,
   but is only called when interrupts are disabled.
 */
 
 static inline
-void BusLogic_LockHostAdapterID(BusLogic_HostAdapter_T *HostAdapter)
+void BusLogic_AcquireHostAdapterLockID(BusLogic_HostAdapter_T *HostAdapter,
+				       BusLogic_Lock_T *Lock)
 {
 }
 
 
 /*
-  BusLogic_UnlockHostAdapterID releases exclusive access to Host Adapter,
+  BusLogic_ReleaseHostAdapterLockID releases exclusive access to Host Adapter,
   but is only called when interrupts are disabled.
 */
 
 static inline
-void BusLogic_UnlockHostAdapterID(BusLogic_HostAdapter_T *HostAdapter)
+void BusLogic_ReleaseHostAdapterLockID(BusLogic_HostAdapter_T *HostAdapter,
+				       BusLogic_Lock_T *Lock)
 {
 }
 
@@ -936,16 +1026,16 @@
 
 
 /*
-  BusLogic_StartMailboxScan issues a Start Mailbox Scan command, which
+  BusLogic_StartMailboxCommand issues an Execute Mailbox Command, which
   notifies the Host Adapter that an entry has been made in an Outgoing
   Mailbox.
 */
 
 static inline
-void BusLogic_StartMailboxScan(BusLogic_HostAdapter_T *HostAdapter)
+void BusLogic_StartMailboxCommand(BusLogic_HostAdapter_T *HostAdapter)
 {
   BusLogic_WriteCommandParameterRegister(HostAdapter,
-					 BusLogic_StartMailboxCommand);
+					 BusLogic_ExecuteMailboxCommand);
 }
 
 
@@ -971,7 +1061,8 @@
 
 static void BusLogic_InterruptHandler(int, void *, Registers_T *);
 static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *,
-				     SCSI_Command_T *);
+				     SCSI_Command_T *,
+				     unsigned int);
 
 
 #endif /* BusLogic_DriverVersion */
diff -u --recursive --new-file v1.3.88/linux/drivers/scsi/ChangeLog linux/drivers/scsi/ChangeLog
--- v1.3.88/linux/drivers/scsi/ChangeLog	Fri Apr 12 15:51:58 1996
+++ linux/drivers/scsi/ChangeLog	Sun Apr 14 11:19:17 1996
@@ -1,3 +1,7 @@
+Sat Apr 13 13:58:00 1996  Leonard N. Zubkoff <lnz@dandelion.com>
+
+	* BusLogic Driver Version 1.3.2 Released.
+
 Sun Dec 31 23:26:00 1995  Leonard N. Zubkoff <lnz@dandelion.com>
 
 	* BusLogic Driver Version 1.3.1 Released.
diff -u --recursive --new-file v1.3.88/linux/drivers/scsi/README.BusLogic linux/drivers/scsi/README.BusLogic
--- v1.3.88/linux/drivers/scsi/README.BusLogic	Fri Apr 12 15:51:59 1996
+++ linux/drivers/scsi/README.BusLogic	Sun Apr 14 11:21:08 1996
@@ -1,5 +1,9 @@
-	       BusLogic MultiMaster SCSI Driver for Linux 1.3.51
-		       Version 1.3.1 ~ 31 December 1995
+		  BusLogic MultiMaster SCSI Driver for Linux
+
+		       Version 1.2.2 for Linux 1.2.13
+		       Version 1.3.2 for Linux 1.3.88
+
+				 13 April 1996
 
 			       Leonard N. Zubkoff
 			       Dandelion Digital
@@ -16,7 +20,8 @@
 driver supports all present BusLogic MultiMaster Host Adapters, and should
 support any future MultiMaster designs with little or no modification.  Host
 adapters based on the new FlashPoint architecture are not supported by this
-driver.
+driver; consult the README.FlashPoint file for information about a program to
+upgrade Linux users from the unsupported FlashPoint LT to the supported BT-948.
 
 My primary goals in writing this completely new BusLogic driver for Linux are
 to achieve the full performance that BusLogic SCSI Host Adapters and modern
@@ -29,7 +34,7 @@
 The most recent versions of this driver will always be available by anonymous
 FTP from ftp.dandelion.com.  While directory listings are not permitted, the
 introductory banner displayed on anonymous FTP login will provide a list of the
-driver versions and any other files available for retrieval.
+driver versions and any other files that are available for retrieval.
 
 Bug reports should be sent via electronic mail to "lnz@dandelion.com".  Please
 include with the bug report the complete configuration messages reported by the
@@ -37,15 +42,25 @@
 relevant to SCSI operations, and a detailed description of your system's
 hardware configuration.
 
-I have recently had conversations with the Senior Product Marketing Manager at
-BusLogic regarding the needs of free software developers, and he has reaffirmed
-BusLogic's commitment to providing the technical information and support we
-need to take full advantage of their products.  BusLogic has also been very
-accommodating in providing technical documentation, as well as access to their
-engineering staff for technical questions and advice.  In addition, they have
-loaned me ISA cards for configuration testing, and even allowed me use of their
-technical support lab to test EISA configurations, since I don't have an EISA
-system.  Their interest and support is greatly appreciated.
+BusLogic has been an excellent company to work with and I highly recommend
+their products to the Linux community.  In November 1995, I was offered the
+opportunity to become a beta test site for their latest MultiMaster product,
+the BT-948 PCI Ultra SCSI Host Adapter, and then again for the BT-958 PCI Wide
+Ultra SCSI Host Adapter in January 1996.  This was mutually beneficial since
+BusLogic received a degree and kind of testing that their own testing group
+cannot readily achieve, and the Linux community has available high performance
+host adapters that have been well tested with Linux even before being brought
+to market.  This relationship has also given me the opportunity to interact
+directly with their technical staff, to understand more about the internal
+workings of their products, and in turn to educate them about the needs and
+potential of the Linux community.  Their interest and support is greatly
+appreciated.
+
+Unlike some other vendors, if you contact BusLogic Technical Support with a
+problem and are running Linux, they will not tell you that your use of their
+products is unsupported.  Their latest product marketing literature even states
+"BusLogic SCSI host adapters are compatible with all major operating systems
+including: ... Linux ...".
 
 BusLogic, Inc. is located at 4151 Burton Drive, Santa Clara, California, 95054,
 USA and can be reached by Voice at 408/492-9090 or by FAX at 408/492-1542.
@@ -82,38 +97,43 @@
   addition, BusLogic's Strict Round Robin Mode is used to optimize host adapter
   performance, and scatter/gather I/O can support as many segments as can be
   effectively utilized by the Linux I/O subsystem.  Control over the use of
-  tagged queuing for each target device as well as selection of the maximum
-  number of concurrent commands per logical unit is available from the kernel
-  command line.  In addition, tagged queuing is automatically disabled whenever
-  the host adapter firmware version is known not to implement it correctly, or
-  whenever a concurrency value of 1 is selected.  Tagged queuing is also
-  disabled for individual target devices if disconnect/reconnect is disabled
-  for that device.  In performance testing, sustained disk writes of 7.3MB per
-  second have been observed to a /dev/sd device.
+  tagged queuing for each target device as well as selection of the tagged
+  queue depth is available from the kernel command line.  By default, the queue
+  depth is automatically determined based on the number, type, speed, and
+  capabilities of the target devices found.  In addition, tagged queuing is
+  automatically disabled whenever the host adapter firmware version is known
+  not to implement it correctly, or whenever a tagged queue depth of 1 is
+  selected.  Tagged queuing is also disabled for individual target devices if
+  disconnect/reconnect is disabled for that device.  In performance testing,
+  sustained disk writes of 7.3MB per second have been observed to a /dev/sd
+  device.
 
 o Robustness Features
 
-  The driver implements extensive error recovery procedures.  By default, when
-  the higher level parts of the SCSI subsystem request that a command be reset,
-  a selection is made between a full host adapter hard reset and SCSI bus reset
-  versus sending a bus device reset message to the individual device based on
-  the recommendation of the SCSI subsystem.  Error recovery options are
-  selectable from the kernel command line individually for each target device,
-  and also include forcing a full host adapter hard reset and SCSI bus reset,
-  sending a bus device reset to the specific target device associated with the
-  command being reset, as well as suppressing error recovery entirely to avoid
+  The driver implements extensive error recovery procedures.  When the higher
+  level parts of the SCSI subsystem request that a command be reset, action is
+  taken to restore proper operation of the host adapter and SCSI bus.  On Linux
+  1.2.13, by default a full host adapter hard reset and SCSI bus reset is
+  performed.  On Linux 1.3.x, by default a selection is made between a full
+  host adapter hard reset and SCSI bus reset versus sending a bus device reset
+  message to the individual target device based on the recommendation of the
+  SCSI subsystem.  Error recovery strategies are selectable from the kernel
+  command line individually for each target device, and also include sending a
+  bus device reset to the specific target device associated with the command
+  being reset, as well as suppressing error recovery entirely to avoid
   perturbing an improperly functioning device.  If the bus device reset error
-  recovery option is selected and sending a bus device reset does not restore
+  recovery strategy is selected and sending a bus device reset does not restore
   correct operation, the next command that is reset will force a full host
   adapter hard reset and SCSI bus reset.  SCSI bus resets caused by other
   devices and detected by the host adapter are also handled by issuing a hard
-  reset to the host adapter and full reinitialization.  Finally, if a command
-  using tagged queuing causes a bus device reset or SCSI bus reset, then tagged
-  queuing will be disabled for that target device.  These error recovery
-  options should improve overall system robustness by preventing individual
-  errant devices from causing the system as a whole to lock up or crash, and
-  thereby allowing a clean shutdown and restart after the offending component
-  is removed.
+  reset to the host adapter and full re-initialization.  Finally, if tagged
+  queuing is active and more than one command reset occurs in a 10 minute
+  interval, or if a command reset occurs within the first 10 minutes of
+  operation, then tagged queuing will be disabled for that target device.
+  These error recovery options should improve overall system robustness by
+  preventing individual errant devices from causing the system as a whole to
+  lock up or crash, and thereby allowing a clean shutdown and restart after the
+  offending component is removed.
 
 o Extensive Testing
 
@@ -132,6 +152,7 @@
   port addresses.  The ISA compatible I/O port address is then disabled by the
   driver.  On PCI systems it is also recommended that the AutoSCSI utility be
   used to disable the ISA compatible I/O port entirely as it is not necessary.
+  The ISA compatible I/O port is disabled by default on the BT-948/958/958D.
 
 o Shared Interrupts Support
 
@@ -159,15 +180,21 @@
 Host Adapter not in the following table contact the author beforehand to verify
 that it is or will be supported.
 
+"W" Series Host Adapters:
+
+BT-948	    PCI	    Ultra Fast Single-ended SCSI-2
+BT-958	    PCI	    Ultra Wide Single-ended SCSI-2
+BT-958D	    PCI	    Ultra Wide Differential SCSI-2
+
 "C" Series Host Adapters:
 
 BT-946C	    PCI	    Fast Single-ended SCSI-2
-BT-956C	    PCI	    Fast/Wide Single-ended SCSI-2
-BT-956CD    PCI	    Fast/Wide Differential SCSI-2
+BT-956C	    PCI	    Fast Wide Single-ended SCSI-2
+BT-956CD    PCI	    Fast Wide Differential SCSI-2
 BT-445C	    VLB	    Fast Single-ended SCSI-2
 BT-747C	    EISA    Fast Single-ended SCSI-2
-BT-757C	    EISA    Fast/Wide Single-ended SCSI-2
-BT-757CD    EISA    Fast/Wide Differential SCSI-2
+BT-757C	    EISA    Fast Wide Single-ended SCSI-2
+BT-757CD    EISA    Fast Wide Differential SCSI-2
 BT-545C	    ISA	    Fast Single-ended SCSI-2
 BT-540CF    ISA	    Fast Single-ended SCSI-2
 
@@ -176,8 +203,8 @@
 BT-445S	    VLB	    Fast Single-ended SCSI-2
 BT-747S	    EISA    Fast Single-ended SCSI-2
 BT-747D	    EISA    Fast Differential SCSI-2
-BT-757S	    EISA    Fast/Wide Single-ended SCSI-2
-BT-757D	    EISA    Fast/Wide Differential SCSI-2
+BT-757S	    EISA    Fast Wide Single-ended SCSI-2
+BT-757D	    EISA    Fast Wide Differential SCSI-2
 BT-545S	    ISA	    Fast Single-ended SCSI-2
 BT-542D	    ISA	    Fast Differential SCSI-2
 BT-742A	    EISA    Single-ended SCSI-2 (742A revision H)
@@ -189,12 +216,67 @@
 BT-542B	    ISA	    Single-ended SCSI-2 (542B revisions A - G)
 
 The FlashPoint LT, also known as the BT-930 Ultra, implements a different host
-interface and is not supported by this driver.
+interface and is not supported by this driver.  Consult the README.FlashPoint
+file for information about a program to upgrade Linux users from the
+unsupported FlashPoint LT to the supported BT-948.
 
-AMI FastDisk Host Adapters are true BusLogic clones and are supported by this
+AMI FastDisk Host Adapters that are true BusLogic clones are supported by this
 driver.
 
 
+		      BT-948/958/958D INSTALLATION NOTES
+
+The BT-948/958/958D PCI Ultra SCSI Host Adapters have some features which may
+require attention in some circumstances when installing Linux.
+
+o PCI I/O Port Assignments
+
+  When configured to factory default settings, the BT-948/958/958D will only
+  recognize the PCI I/O port assignments made by the motherboard's PCI BIOS.
+  The BT-948/958/958D will not respond to any of the ISA compatible I/O ports
+  that previous BusLogic SCSI Host Adapters respond to.  This driver supports
+  the PCI I/O port assignments, so this is the preferred configuration.
+  However, if the obsolete BusLogic driver must be used for any reason, such as
+  a Linux distribution that does not yet use this driver in its boot kernel,
+  BusLogic has provided an AutoSCSI configuration option to enable a legacy ISA
+  compatible I/O port.
+
+  To enable this backward compatibility option, invoke the AutoSCSI utility via
+  Ctrl-B at system startup and select "Adapter Configuration", "View/Modify
+  Configuration", and then change the "ISA Compatible Port" setting from
+  "Disable" to "Primary" or "Alternate".  Once this driver has been installed,
+  the "ISA Compatible Port" option should be set back to "Disable" to avoid
+  possible future I/O port conflicts.  The older BT-946C/956C/956CD also have
+  this configuration option, but the factory default setting is "Primary".
+
+o PCI Slot Scanning Order
+
+  In systems with multiple BusLogic PCI Host Adapters, the order in which the
+  PCI slots are scanned may appear reversed with the BT-948/958/958D as
+  compared to the BT-946C/956C/956CD.  For booting from a SCSI disk to work
+  correctly, it is necessary that the host adapter's BIOS and the kernel agree
+  on which disk is the boot device, which requires that they recognize the PCI
+  host adapters in the same order.  The motherboard's PCI BIOS provides a
+  standard way of enumerating the PCI host adapters, which is used by the Linux
+  kernel.  Some PCI BIOS implementations enumerate the PCI slots in order of
+  increasing bus number and device number, while others do so in the opposite
+  direction.
+
+  Unfortunately, Microsoft decided that Windows 95 would always enumerate the
+  PCI slots in order of increasing bus number and device number regardless of
+  the PCI BIOS enumeration, and requires that their scheme be supported by the
+  host adapter's BIOS to receive Windows 95 certification.  Therefore, the
+  factory default settings of the BT-948/958/958D enumerate the host adapters
+  by increasing bus number and device number.  To disable this feature, invoke
+  the AutoSCSI utility via Ctrl-B at system startup and select "Adapter
+  Configuration", "View/Modify Configuration", press Ctrl-F10, and then change
+  the "Use Bus And Device # For PCI Scanning Seq." option to OFF.
+
+  This driver will interrogate the setting of the PCI Scanning Sequence option
+  so as to recognize the host adapters in the same order as they are enumerated
+  by the host adapter's BIOS.
+
+
 			     COMMAND LINE OPTIONS
 
 Many features of this driver are configurable by specification of appropriate
@@ -208,49 +290,51 @@
 
   "BusLogic=0,1"
 
-    This command line selects default probing and a concurrency of 1 which also
-    disables tagged queuing.  It may be useful if problems arise during
-    installation on a system with a flaky SCSI configuration.  In cases of a
-    marginal SCSI configuration it may also be beneficial to disable fast
-    transfers and/or synchronous negotiation using AutoSCSI on "C" series
-    boards.  Disconnect/reconnect may also be disabled for fast devices such as
-    disk drives, but should not be disabled for tape drives or other devices
-    where a single command may take over a second to execute.
+    This command line selects default probing and a tagged queue depth of 1
+    which also disables tagged queuing.  It may be useful if problems arise
+    during installation on a system with a flaky SCSI configuration.  In cases
+    of a marginal SCSI configuration it may also be beneficial to disable fast
+    transfers and/or synchronous negotiation using AutoSCSI on "W" and "C"
+    series boards.  Disconnect/reconnect may also be disabled for fast devices
+    such as disk drives, but should not be disabled for tape drives or other
+    devices where a single command may take over a second to execute.
 
   "BusLogic=0,0,10"
 
-    This command line selects default probing and concurrency but changes the
-    bus settle time to 10 seconds.  It may be useful with SCSI devices that
-    take an unusually long time to become ready to accept commands after a SCSI
-    bus reset.
+    This command line selects default probing and automatic tagged queue depth
+    selection, but changes the bus settle time to 10 seconds.  It may be useful
+    with SCSI devices that take an unusually long time to become ready to
+    accept commands after a SCSI bus reset.
 
   "BusLogic=TQ:Disable"
 
-    This command line selects default probing and disables tagged queuing,
-    while keeping the default concurrency.
+    This command line selects default probing and disables tagged queuing.
 
   "BusLogic=0,15,TQ:N"
 
-    This command line selects a concurrency of 15 and disables tagged queuing
-    for target 0, while allowing tagged queuing for all other target devices.
+    This command line selects a tagged queue depth of 15 and disables tagged
+    queuing for target 0, while allowing tagged queuing for all other target
+    devices.
 
-Note that limiting the concurrency to 1 or disabling tagged queuing can
+Note that limiting the tagged queue depth or disabling tagged queuing can
 substantially impact performance.
 
 
-				 INSTALLATION
+			     INSTALLATION
 
-This distribution was prepared for Linux kernel version 1.3.51.  Installation
-in later versions will probably be successful as well, though BusLogic.patch
-may not be required.  Installation in Linux 1.3.41 - 1.3.50 will probably be
-successful, but may require minor modifications.
+This distribution was prepared for Linux kernel version 1.2.13
+(BusLogic-1.2.2.tar.gz) or Linux kernel version 1.3.88 (BusLogic-1.3.2.tar.gz).
+Installation in later versions will probably be successful as well, though
+BusLogic.patch may not be required.  Installation in earlier versions is not
+recommended.
 
 To install the BusLogic SCSI driver, you may use the following commands,
-replacing "/usr/src" with wherever you keep your Linux kernel source tree:
+replacing "/usr/src" with wherever you keep your Linux kernel source tree
+(substitute '2' or '3' for 'x' in the tar command as appropriate):
 
   cd /usr/src
-  tar -xvzf BusLogic-1.3.1.tar.gz
-  mv README.BusLogic BusLogic.[ch] linux/drivers/scsi
+  tar -xvzf BusLogic-1.x.2.tar.gz
+  mv README.* BusLogic.[ch] linux/drivers/scsi
   patch -p < BusLogic.patch
   cd linux
   make config
@@ -262,4 +346,14 @@
 
 Be sure to answer "y" to the "BusLogic SCSI support" query during the "make
 config" step.  If your system was already configured for the old BusLogic
-driver, you may omit the "make config" step above.
+driver or for an older version of this driver, you may omit the "make config"
+step above.
+
+
+		      BUSLOGIC ANNOUNCEMENTS MAILING LIST
+
+The BusLogic Announcements Mailing List provides a forum for informing Linux
+users of new driver releases and other announcements regarding Linux support
+for BusLogic SCSI Host Adapters.  To join the mailing list, send a message to
+"buslogic-announce-request@dandelion.com" with the line "subscribe" in the
+message body.
diff -u --recursive --new-file v1.3.88/linux/drivers/scsi/README.FlashPoint linux/drivers/scsi/README.FlashPoint
--- v1.3.88/linux/drivers/scsi/README.FlashPoint	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/README.FlashPoint	Sun Apr 14 11:21:08 1996
@@ -0,0 +1,90 @@
+
+				 ANNOUNCEMENT
+		  BusLogic FlashPoint/BT-948 Upgrade Program
+				1 February 1996
+
+Ever since its introduction last October, the BusLogic FlashPoint LT has
+been problematic for members of the Linux community, in that no Linux
+drivers have been available for this new Ultra SCSI product.  Despite it's
+officially being positioned as a desktop workstation product, and not being
+particularly well suited for a high performance multitasking operating
+system like Linux, the FlashPoint LT has been touted by computer system
+vendors as the latest thing, and has been sold even on many of their high
+end systems, to the exclusion of the older MultiMaster products.  This has
+caused grief for many people who inadvertently purchased a system expecting
+that all BusLogic SCSI Host Adapters were supported by Linux, only to
+discover that the FlashPoint was not supported and would not be for quite
+some time, if ever.
+
+After this problem was identified, BusLogic contacted its major OEM
+customers to make sure the BT-946C/956C MultiMaster cards would still be
+made available, and that Linux users who mistakenly ordered systems with
+the FlashPoint would be able to upgrade to the BT-946C.  While this helped
+many purchasers of new systems, it was only a partial solution to the
+overall problem of FlashPoint support for Linux users.  It did nothing to
+assist the people who initially purchased a FlashPoint for a supported
+operating system and then later decided to run Linux, or those who had
+ended up with a FlashPoint LT, believing it was supported, and were unable
+to return it.
+
+In the middle of December, I asked to meet with BusLogic's senior
+management to discuss the issues related to Linux and free software support
+for the FlashPoint.  Rumors of varying accuracy had been circulating
+publicly about BusLogic's attitude toward the Linux community, and I felt
+it was best that these issues be addressed directly.  I sent an email
+message after 11pm one evening, and the meeting took place the next
+afternoon.  Unfortunately, corporate wheels sometimes grind slowly,
+especially when a company is being acquired, and so it's taken until now
+before the details were completely determined and a public statement could
+be made.
+
+BusLogic is not prepared at this time to release the information necessary
+for third parties to write drivers for the FlashPoint.  The only existing
+FlashPoint drivers have been written directly by BusLogic Engineering, and
+there is no FlashPoint documentation sufficiently detailed to allow outside
+developers to write a driver without substantial assistance.  While there
+are people at BusLogic who would rather not release the details of the
+FlashPoint architecture at all, that debate has not yet been settled either
+way.  In any event, even if documentation were available today it would
+take quite a while for a usable driver to be written, especially since I'm
+not convinced that the effort required would be worthwhile.
+
+However, BusLogic does remain committed to providing a high performance
+SCSI solution for the Linux community, and does not want to see anyone left
+unable to run Linux because they have a Flashpoint LT.  Therefore, BusLogic
+has put in place a direct upgrade program to allow any Linux user worldwide
+to trade in their FlashPoint LT for the new BT-948 MultiMaster PCI Ultra
+SCSI Host Adapter.  The BT-948 is the Ultra SCSI successor to the BT-946C
+and has all the best features of both the BT-946C and FlashPoint LT,
+including smart termination and a flash PROM for easy firmware updates, and
+is of course compatible with the present Linux driver.  The price for this
+upgrade has been set at US $45, and the upgrade program will be
+administered through BusLogic Technical Support, which can be reached by
+electronic mail at techsup@buslogic.com, by Voice at +1 408 654-0760, or by
+FAX at +1 408 492-1542.
+
+I was a beta test site for the BT-948 and versions 1.2.1 and 1.3.1 of my
+BusLogic driver already include latent support for the BT-948.  Additional
+cosmetic support for the Ultra SCSI MultiMaster cards will be added in a
+subsequent release.  As a result of this cooperative testing process,
+several firmware bugs were found and corrected (make sure you have firmware
+version 5.05R or later).  My heavily loaded Linux test system provided an
+ideal environment for testing error recovery processes that are much more
+rarely exercised in production systems, but are crucial to overall system
+stability.  It was especially convenient being able to work directly with
+their firmware engineer in demonstrating the problems under control of the
+firmware debugging environment; things sure have come a long way since the
+last time I worked on firmware for an embedded system.  I am presently
+working on some performance testing and expect to have some data to report
+in the not too distant future.
+
+BusLogic asked me to send this announcement since a large percentage of the
+questions regarding support for the FlashPoint have either been sent to me
+directly via email, or have appeared in the Linux newsgroups in which I
+participate.  To summarize, BusLogic is offering Linux users an upgrade
+from the unsupported FlashPoint LT (BT-930) to the supported BT-948 for US
+$45.  Contact BusLogic Technical Support at techsup@buslogic.com or +1 408
+654-0760 to take advantage of their offer.
+
+		Leonard N. Zubkoff
+		lnz@dandelion.com
diff -u --recursive --new-file v1.3.88/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c
--- v1.3.88/linux/drivers/scsi/aha1542.c	Tue Apr  2 13:32:21 1996
+++ linux/drivers/scsi/aha1542.c	Sun Apr 14 11:19:17 1996
@@ -1179,7 +1179,7 @@
    For a first go, we assume that the 1542 notifies us with all of the
    pending commands (it does implement soft reset, after all). */
 
-int aha1542_reset(Scsi_Cmnd * SCpnt)
+int aha1542_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
 {
     unchar ahacmd = CMD_START_SCSI;
     int i;
@@ -1187,7 +1187,7 @@
     /*
      * See if a bus reset was suggested.
      */
-    if( SCpnt->host->suggest_bus_reset )
+    if( reset_flags & SCSI_RESET_SUGGEST_BUS_RESET )
       {
 	/* 
 	 * This does a scsi reset for all devices on the bus.
diff -u --recursive --new-file v1.3.88/linux/drivers/scsi/aha1542.h linux/drivers/scsi/aha1542.h
--- v1.3.88/linux/drivers/scsi/aha1542.h	Thu Sep 21 09:01:48 1995
+++ linux/drivers/scsi/aha1542.h	Sun Apr 14 11:19:17 1996
@@ -134,7 +134,7 @@
 int aha1542_command(Scsi_Cmnd *);
 int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int aha1542_abort(Scsi_Cmnd *);
-int aha1542_reset(Scsi_Cmnd *);
+int aha1542_reset(Scsi_Cmnd *, unsigned int);
 int aha1542_biosparam(Disk *, kdev_t, int*);
 
 #define AHA1542_MAILBOXES 8
diff -u --recursive --new-file v1.3.88/linux/drivers/scsi/g_NCR5380.c linux/drivers/scsi/g_NCR5380.c
--- v1.3.88/linux/drivers/scsi/g_NCR5380.c	Fri Apr 12 15:52:00 1996
+++ linux/drivers/scsi/g_NCR5380.c	Mon Apr 15 11:58:23 1996
@@ -122,13 +122,15 @@
     static int commandline_current = 0;
     switch (board) {
     case BOARD_NCR5380:
-	if (ints[0] != 2 && ints[0] != 3) 
+	if (ints[0] != 2 && ints[0] != 3) {
 	    printk("generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n");
-	return;
+	    return;
+	}
     case BOARD_NCR53C400:
-	if (ints[0] != 2)
-	    printk("generic_NCR53C400_setup : usage ncr53c400= " STRVAL(NCR5380_map_name) ",irq\n");
-	return;
+	if (ints[0] != 2) {
+	    printk("generic_NCR53C400_setup : usage ncr53c400=" STRVAL(NCR5380_map_name) ",irq\n");
+	    return;
+	}
     }
 
     if (commandline_current < NO_OVERRIDES) {
diff -u --recursive --new-file v1.3.88/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v1.3.88/linux/drivers/scsi/hosts.c	Wed Apr 10 17:02:25 1996
+++ linux/drivers/scsi/hosts.c	Sun Apr 14 11:19:17 1996
@@ -333,6 +333,9 @@
     retval->cmd_per_lun = tpnt->cmd_per_lun;
     retval->unchecked_isa_dma = tpnt->unchecked_isa_dma;
     retval->use_clustering = tpnt->use_clustering;   
+
+    retval->select_queue_depths = NULL;
+
     if(!scsi_hostlist)
 	scsi_hostlist = retval;
     else
diff -u --recursive --new-file v1.3.88/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h
--- v1.3.88/linux/drivers/scsi/hosts.h	Sun Jan 14 16:41:58 1996
+++ linux/drivers/scsi/hosts.h	Sun Apr 14 11:19:17 1996
@@ -156,7 +156,7 @@
      * and these hosts must call scsi_request_sense(SCpnt) to keep
      * the command alive.
      */ 
-    int (* reset)(Scsi_Cmnd *);
+    int (* reset)(Scsi_Cmnd *, unsigned int);
 
     /*
      * This function is used to select synchronous communications,
@@ -246,7 +246,7 @@
     char host_no;  /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
     int last_reset;
     struct wait_queue *host_wait;
-    Scsi_Cmnd *host_queue; 
+    Scsi_Cmnd *host_queue;
     Scsi_Host_Template * hostt;
     
     /*
@@ -298,13 +298,9 @@
      * True if this host was loaded as a loadable module
      */
     unsigned loaded_as_module:1;
-    
-    /*
-     * True when we call the low-level reset function, and
-     * the midlevel code suggests a full bus reset.
-     */
-    unsigned suggest_bus_reset:1;
  
+    void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *);
+
     unsigned long hostdata[0];  /* Used for storage of host specific stuff */
 };
 
diff -u --recursive --new-file v1.3.88/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.3.88/linux/drivers/scsi/scsi.c	Sat Apr 13 18:22:07 1996
+++ linux/drivers/scsi/scsi.c	Sun Apr 14 11:19:17 1996
@@ -84,7 +84,7 @@
 static void scsi_done (Scsi_Cmnd *SCpnt);
 static int update_timeout (Scsi_Cmnd *, int);
 static void print_inquiry(unsigned char *data);
-static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid);
+static void scsi_times_out (Scsi_Cmnd * SCpnt);
 static int scan_scsis_single (int channel,int dev,int lun,int * max_scsi_dev ,
                  Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt,
                  struct Scsi_Host *shpnt, char * scsi_result);
@@ -134,6 +134,8 @@
 /* Process ID of SCSI commands */
 unsigned long scsi_pid = 0;
 
+static unsigned long serial_number = 0;
+
 static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
 static void resize_dma_pool(void);
 
@@ -150,13 +152,12 @@
 
 struct proc_dir_entry proc_scsi_scsi = {
     PROC_SCSI_SCSI, 4, "scsi",
-    S_IFREG | S_IRUGO | S_IWUSR, 2, 0, 0, 0, 
+    S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0, 
     NULL,
     NULL, NULL,
     NULL, NULL, NULL
 };
 
-
 /*
  *  As the scsi do command functions are intelligent, and may need to
  *  redo a command, we need to keep track of the last command
@@ -484,16 +485,16 @@
   leave:
 
   {/* Unchain SCpnt from host_queue */
-    Scsi_Cmnd *prev,*next,*hqptr;
-    for(hqptr=shpnt->host_queue; hqptr!=SCpnt; hqptr=hqptr->next) ;
+    Scsi_Cmnd *prev, *next, *hqptr;
+    for(hqptr = shpnt->host_queue; hqptr != SCpnt; hqptr = hqptr->next) ;
     if(hqptr) {
-      prev=hqptr->prev;
-      next=hqptr->next;
+      prev = hqptr->prev;
+      next = hqptr->next;
       if(prev) 
-     	prev->next=next;
+     	prev->next = next;
       else 
-     	shpnt->host_queue=next;
-      if(next) next->prev=prev;
+     	shpnt->host_queue = next;
+      if(next) next->prev = prev;
     }
   }
  
@@ -810,6 +811,7 @@
 #define NORMAL_TIMEOUT 0
 #define IN_ABORT 1
 #define IN_RESET 2
+#define IN_RESET2 4
 
 /*
  * This is our time out function, called when the timer expires for a
@@ -817,10 +819,10 @@
  * command, that failing perform a kernel panic.
  */
 
-static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid)
+static void scsi_times_out (Scsi_Cmnd * SCpnt)
 {
     
-    switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET))
+    switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2))
     {
     case NORMAL_TIMEOUT:
 	{
@@ -829,12 +831,12 @@
 #endif
 	}
 	
-	if (!scsi_abort (SCpnt, DID_TIME_OUT, pid))
+	if (!scsi_abort (SCpnt, DID_TIME_OUT))
 	    return;
     case IN_ABORT:
 	printk("SCSI host %d abort (pid %ld) timed out - resetting\n",
 	       SCpnt->host->host_no, SCpnt->pid);
-	if (!scsi_reset (SCpnt, FALSE))
+	if (!scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS))
 	    return;
     case IN_RESET:
     case (IN_ABORT | IN_RESET):
@@ -842,14 +844,20 @@
 	 * you might conceivably want the machine up and running
 	 * esp if you have an ide disk. 
 	 */
-	printk("Unable to reset scsi host %d - ", SCpnt->host->host_no);
-	printk("probably a SCSI bus hang.\n");
+	printk("SCSI host %d reset (pid %ld) timed out - trying harder\n",
+	       SCpnt->host->host_no, SCpnt->pid);
 	SCpnt->internal_timeout &= ~IN_RESET;
-        scsi_reset (SCpnt, TRUE);
+	SCpnt->internal_timeout |= IN_RESET2;
+        scsi_reset (SCpnt,
+		    SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET);
 	return;
 	
     default:
-	INTERNAL_ERROR;
+	printk("SCSI host %d reset (pid %ld) timed out again -\n",
+	       SCpnt->host->host_no, SCpnt->pid);
+	printk("probably an unrecoverable SCSI bus or device hang.\n");
+	return;
+
     }
     
 }
@@ -874,8 +882,6 @@
     
     if (req && req->rq_status == RQ_INACTIVE)
 	panic("Inactive in request_queueable");
-    
-    SCpnt =  device->host->host_queue;
 
     /*
      * Look for a free command block.  If we have been instructed not to queue
@@ -883,18 +889,17 @@
      * going for this device first.
      */
       
-    SCpnt = device->host->host_queue;
     if (!device->single_lun) {
+	SCpnt = device->device_queue;
 	while(SCpnt){
-	    if(SCpnt->target == device->id &&
-	       SCpnt->lun == device->lun) {
-		if(SCpnt->request.rq_status == RQ_INACTIVE) break;
-	    }
-	    SCpnt = SCpnt->next;
+	    if(SCpnt->request.rq_status == RQ_INACTIVE) break;
+	    SCpnt = SCpnt->device_next;
 	}
     } else {
+	SCpnt = device->host->host_queue;
 	while(SCpnt){
-	    if(SCpnt->target == device->id) {
+	    if(SCpnt->channel == device->channel 
+                && SCpnt->target == device->id) {
 		if (SCpnt->lun == device->lun) {
 		    if(found == NULL 
 		       && SCpnt->request.rq_status == RQ_INACTIVE) 
@@ -1014,19 +1019,18 @@
     if (intr_count && SCSI_BLOCK(host)) return NULL;
     
     while (1==1){
-	SCpnt = device->host->host_queue;
 	if (!device->single_lun) {
+	    SCpnt = device->device_queue;
 	    while(SCpnt){
-		if(SCpnt->target == device->id &&
-		   SCpnt->lun == device->lun) {
-		   SCwait = SCpnt;
-		    if(SCpnt->request.rq_status == RQ_INACTIVE) break;
-		}
-		SCpnt = SCpnt->next;
+		SCwait = SCpnt;
+		if(SCpnt->request.rq_status == RQ_INACTIVE) break;
+		SCpnt = SCpnt->device_next;
 	    }
 	} else {
+	    SCpnt = device->host->host_queue;
 	    while(SCpnt){
-		if(SCpnt->target == device->id) {
+		if(SCpnt->channel == device->channel 
+                   && SCpnt->target == device->id) {
 		    if (SCpnt->lun == device->lun) {
 			SCwait = SCpnt;
 			if(found == NULL 
@@ -1061,15 +1065,16 @@
 	if (!SCpnt || SCpnt->request.rq_status != RQ_INACTIVE)	/* Might have changed */
 	{
 #if 1	/* NEW CODE */
-		if (wait && SCwait && SCwait->request.rq_status != RQ_INACTIVE) {
+		if (wait && SCwait && SCwait->request.rq_status != RQ_INACTIVE){
  			sleep_on(&device->device_wait);
  			restore_flags(flags);
 	 	} else {
  			restore_flags(flags);
 	 		if (!wait) return NULL;
  			if (!SCwait) {
-	 			printk("Attempt to allocate device target %d, lun %d\n",
- 					device->id ,device->lun);
+	 			printk("Attempt to allocate device channel %d,"
+                                       " target %d, lun %d\n", device->channel,
+                                       device->id, device->lun);
  				panic("No device found in allocate_device\n");
 	 		}
  		}
@@ -1077,8 +1082,9 @@
 		    restore_flags(flags);
 		    if(!wait) return NULL;
 		    if (!SCwait) {
-			printk("Attempt to allocate device channel %d, target %d, "
-			       "lun %d\n", device->channel, device->id, device->lun);
+			printk("Attempt to allocate device channel %d, target"
+                               " %d, lun %d\n", device->channel, device->id, 
+                               device->lun);
 			panic("No device found in allocate_device\n");
 		    }
 		    SCSI_SLEEP(&device->device_wait,
@@ -1166,6 +1172,10 @@
      * we can avoid the drive not being ready.
      */
     save_flags(flags);
+    cli();
+    /* Assign a unique nonzero serial_number. */
+    if (++serial_number == 0) serial_number = 1;
+    SCpnt->serial_number = serial_number;
     sti();
     temp = host->last_reset + MIN_RESET_DELAY;
     while (jiffies < temp);
@@ -1326,6 +1336,8 @@
     SCpnt->target = target;
     SCpnt->lun = (SCpnt->data_cmnd[1] >> 5);
 #endif
+    SCpnt->reset_chain = NULL;
+    SCpnt->serial_number = 0;
     SCpnt->bufflen = bufflen;
     SCpnt->buffer = buffer;
     SCpnt->flags=0;
@@ -1449,6 +1461,7 @@
     int oldto;
     struct Scsi_Host * host = SCpnt->host;
     int result = SCpnt->result;
+    SCpnt->serial_number = 0;
     oldto = update_timeout(SCpnt, 0);
     
 #ifdef DEBUG_TIMEOUT
@@ -1486,7 +1499,9 @@
 	    /* Failed to obtain sense information */
 	{
 	    SCpnt->flags &= ~WAS_SENSE;
+#if 0	/* This cannot possibly be correct. */
 	    SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
+#endif
 	    
 	    if (!(SCpnt->flags & WAS_RESET))
 	    {
@@ -1494,7 +1509,7 @@
 		       " failed, performing reset.\n",
 		       SCpnt->host->host_no, SCpnt->channel, SCpnt->target, 
 		       SCpnt->lun);
-		scsi_reset(SCpnt, FALSE);
+		scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
 		return;
 	    }
 	    else
@@ -1515,7 +1530,9 @@
 		    printk ("In scsi_done, GOOD status, COMMAND COMPLETE, parsing sense information.\n");
 #endif
 		    SCpnt->flags &= ~WAS_SENSE;
+#if 0	/* This cannot possibly be correct. */
 		    SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
+#endif
 		    
 		    switch (checked = check_sense(SCpnt))
 		    {
@@ -1595,7 +1612,7 @@
 	    case RESERVATION_CONFLICT:
 		printk("scsi%d, channel %d : RESERVATION CONFLICT performing"
 		       " reset.\n", SCpnt->host->host_no, SCpnt->channel);
-		scsi_reset(SCpnt, FALSE);
+		scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
 		return;
 #if 0
 		exit = DRIVER_SOFT | SUGGEST_ABORT;
@@ -1717,7 +1734,7 @@
 	    {
 		printk("scsi%d channel %d : resetting for second half of retries.\n",
 		       SCpnt->host->host_no, SCpnt->channel);
-		scsi_reset(SCpnt, FALSE);
+		scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
 		break;
 	    }
 	    
@@ -1798,7 +1815,7 @@
  */
 
 
-int scsi_abort (Scsi_Cmnd * SCpnt, int why, int pid)
+int scsi_abort (Scsi_Cmnd * SCpnt, int why)
 {
     int oldto;
     unsigned long flags;
@@ -1813,7 +1830,7 @@
 	 * Protect against races here.  If the command is done, or we are
 	 * on a different command forget it.
 	 */
-	if (SCpnt->request.rq_status == RQ_INACTIVE || pid != SCpnt->pid) {
+	if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
 	    restore_flags(flags);
 	    return 0;
 	}
@@ -1849,7 +1866,7 @@
 		   SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->channel, 
 		   (int) SCpnt->target, (int) SCpnt->lun);
 	    print_command (SCpnt->cmnd);
-	    if (SCpnt->request.rq_status == RQ_INACTIVE || pid != SCpnt->pid)
+	    if (SCpnt->serial_number != SCpnt->serial_number_at_timeout)
 		return 0;
 	    SCpnt->abort_reason = why;
 	    switch(host->hostt->abort(SCpnt)) {
@@ -1926,9 +1943,9 @@
 }
 
 
-int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
+int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
 {
-    int temp, oldto;
+    int temp;
     unsigned long flags;
     Scsi_Cmnd * SCpnt1;
     struct Scsi_Host * host = SCpnt->host;
@@ -1936,6 +1953,7 @@
     printk("SCSI bus is being reset for host %d.\n",
 	   host->host_no);
  
+#if 0
     /*
      * First of all, we need to make a recommendation to the low-level
      * driver as to whether a BUS_DEVICE_RESET should be performed,
@@ -1952,6 +1970,13 @@
      * result in some race conditions, but no more than
      * you would usually get with timeouts.  We will cross
      * that bridge when we come to it.
+     *
+     * This is actually a pretty bad idea, since a sequence of
+     * commands will often timeout together and this will cause a
+     * Bus Device Reset followed immediately by a SCSI Bus Reset.
+     * If all of the active devices really are jammed up, the
+     * Bus Device Reset will quickly timeout and scsi_times_out
+     * will follow up with a SCSI Bus Reset anyway.
      */
     SCpnt1 = host->host_queue;
     while(SCpnt1) {
@@ -1961,22 +1986,34 @@
         SCpnt1 = SCpnt1->next;
  	}
     if( SCpnt1 == NULL ) {
-        SCpnt->host->suggest_bus_reset = TRUE;
+        reset_flags |= SCSI_RESET_SUGGEST_BUS_RESET;
     }
     
-    
     /*
      * If the code that called us is suggesting a hard reset, then
      * definitely request it.  This usually occurs because a
      * BUS_DEVICE_RESET times out.
+     *
+     * Passing reset_flags along takes care of this automatically.
      */
-    if( bus_reset_flag ) {
+    if( reset_flags & SCSI_RESET_SUGGEST_BUS_RESET ) {
         SCpnt->host->suggest_bus_reset = TRUE;
     }
+#endif
     
     while (1) {
 	save_flags(flags);
 	cli();
+
+	/*
+	 * Protect against races here.  If the command is done, or we are
+	 * on a different command forget it.
+	 */
+	if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
+	    restore_flags(flags);
+	    return 0;
+	}
+
 	if (SCpnt->internal_timeout & IN_RESET)
 	{
 	    restore_flags(flags);
@@ -1986,7 +2023,7 @@
 	else
 	{
 	    SCpnt->internal_timeout |= IN_RESET;
-	    oldto = update_timeout(SCpnt, RESET_TIMEOUT);
+	    update_timeout(SCpnt, RESET_TIMEOUT);
 	    
 	    if (host->host_busy)
 	    {
@@ -1997,7 +2034,7 @@
 #if 0
 			if (!(SCpnt1->flags & IS_RESETTING) &&
 			    !(SCpnt1->internal_timeout & IN_ABORT))
-			    scsi_abort(SCpnt1, DID_RESET, SCpnt->pid);
+			    scsi_abort(SCpnt1, DID_RESET);
 #endif
 			SCpnt1->flags |= (WAS_RESET | IS_RESETTING);
 		    }
@@ -2005,7 +2042,7 @@
 		}
 		
 		host->last_reset = jiffies;
-		temp = host->hostt->reset(SCpnt);
+		temp = host->hostt->reset(SCpnt, reset_flags);
 		host->last_reset = jiffies;
 	    }
 	    else
@@ -2014,7 +2051,7 @@
 		restore_flags(flags);
 		host->last_reset = jiffies;
 	        SCpnt->flags |= (WAS_RESET | IS_RESETTING);
-		temp = host->hostt->reset(SCpnt);
+		temp = host->hostt->reset(SCpnt, reset_flags);
 		host->last_reset = jiffies;
 		if (!host->block) host->host_busy--;
 	    }
@@ -2040,13 +2077,13 @@
 		save_flags(flags);
 		cli();
 		SCpnt->internal_timeout &= ~IN_RESET;
-		update_timeout(SCpnt, oldto);
 		restore_flags(flags);
 		return 0;
 	    case SCSI_RESET_PENDING:
 	        if (temp & SCSI_RESET_BUS_RESET)
 		  scsi_mark_host_bus_reset(host);
 		else scsi_mark_device_reset(SCpnt->device);
+	    case SCSI_RESET_NOT_RUNNING:
 		return 0;
 	    case SCSI_RESET_PUNT:
                 SCpnt->internal_timeout &= ~IN_RESET;
@@ -2103,36 +2140,43 @@
      * We must not enter update_timeout with a timeout condition still pending.
      */
     
-    int timed_out, pid;
+    int timed_out;
     unsigned long flags;
     struct Scsi_Host * host;
     Scsi_Cmnd * SCpnt = NULL;
     
-    do {
-	save_flags(flags);
-	cli();
-	
-	update_timeout(NULL, 0);
-	/*
-	 * Find all timers such that they have 0 or negative (shouldn't happen)
-	 * time remaining on them.
-	 */
-	
-	timed_out = 0;
-	for(host = scsi_hostlist; host; host = host->next) {
-	    for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
-		if (SCpnt->timeout == -1)
-		{
-		    SCpnt->timeout = 0;
-		    pid = SCpnt->pid;
+    save_flags(flags);
+    cli();
+
+    update_timeout(NULL, 0);
+
+    /*
+     * Find all timers such that they have 0 or negative (shouldn't happen)
+     * time remaining on them.
+     */
+    timed_out = 0;
+    for (host = scsi_hostlist; host; host = host->next) {
+	for (SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
+	    if (SCpnt->timeout == -1)
+	      {
+		SCpnt->timeout = 0;
+		SCpnt->serial_number_at_timeout = SCpnt->serial_number;
+		++timed_out;
+	      }
+    }
+    if (timed_out > 0) {
+	for (host = scsi_hostlist; host; host = host->next) {
+	    for (SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
+		if (SCpnt->serial_number_at_timeout > 0 &&
+		    SCpnt->serial_number_at_timeout == SCpnt->serial_number)
+		  {
 		    restore_flags(flags);
-		    scsi_times_out(SCpnt, pid);
-		    ++timed_out;
-		    save_flags(flags);
+		    scsi_times_out(SCpnt);
+		    SCpnt->serial_number_at_timeout = 0;
 		    cli();
-		}
-	}
-    } while (timed_out);
+		  }
+	  }
+    }
     restore_flags(flags);
 }
 
@@ -2155,6 +2199,27 @@
     save_flags(flags);
     cli();
 
+    oldto = 0;
+
+    /*
+     * This routine can be a performance bottleneck under high loads, since
+     * it is called twice per SCSI operation: once when internal_cmnd is
+     * called, and again when scsi_done completes the command.  To limit
+     * the load this routine can cause, we shortcut processing if no clock
+     * ticks have occurred since the last time it was called.  This may
+     * cause the computation of least below to be inaccurrate, but it will
+     * be corrected after the next clock tick.
+     */
+
+    if (jiffies == time_start && timer_table[SCSI_TIMER].expires > 0) {
+	if(SCset){
+	    oldto = SCset->timeout;
+	    SCset->timeout = timeout;
+	}
+	restore_flags(flags);
+	return oldto;
+    }
+
     /*
      * Figure out how much time has passed since the last time the timeouts
      * were updated
@@ -2180,7 +2245,7 @@
 	for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
 	    if (SCpnt->timeout > 0) {
 	        if (SCpnt != SCset)
-		  SCpnt->timeout -= used;
+		    SCpnt->timeout -= used;
 		if(SCpnt->timeout <= 0) SCpnt->timeout = -1;
 		if(SCpnt->timeout > 0 && SCpnt->timeout < least)
 		    least = SCpnt->timeout;
@@ -2323,16 +2388,19 @@
 
 void scsi_build_commandblocks(Scsi_Device * SDpnt)
 {
+    struct Scsi_Host *host = SDpnt->host;
     int j;
-    Scsi_Cmnd * SCpnt;
-    struct Scsi_Host * host = NULL;
-    
-    for(j=0;j<SDpnt->host->cmd_per_lun;j++){
-	host = SDpnt->host;
-	SCpnt = (Scsi_Cmnd *)
-		scsi_init_malloc(sizeof(Scsi_Cmnd),
-				 GFP_ATOMIC |
-				 (host->unchecked_isa_dma ? GFP_DMA : 0));
+    Scsi_Cmnd * SCpnt;                 
+
+    if (SDpnt->queue_depth == 0)
+        SDpnt->queue_depth = host->cmd_per_lun;
+    SDpnt->device_queue = NULL;
+ 
+    for(j=0;j<SDpnt->queue_depth;j++){
+      SCpnt = (Scsi_Cmnd *)
+              scsi_init_malloc(sizeof(Scsi_Cmnd),
+                               GFP_ATOMIC |
+                               (host->unchecked_isa_dma ? GFP_DMA : 0));
 	SCpnt->host = host;
 	SCpnt->device = SDpnt;
 	SCpnt->target = SDpnt->id;
@@ -2345,12 +2413,16 @@
 	SCpnt->timeout = 0;
 	SCpnt->underflow = 0;
 	SCpnt->transfersize = 0;
+	SCpnt->serial_number = 0;
+	SCpnt->serial_number_at_timeout = 0;
 	SCpnt->host_scribble = NULL;
 	if(host->host_queue)
 	    host->host_queue->prev = SCpnt;
 	SCpnt->next = host->host_queue;
 	SCpnt->prev = NULL;
 	host->host_queue = SCpnt;
+	SCpnt->device_next = SDpnt->device_queue;
+	SDpnt->device_queue = SCpnt;
     }
     SDpnt->has_cmdblocks = 1;
 }
@@ -2392,8 +2464,11 @@
 
     scsi_devices = (Scsi_Device *) NULL;
 
-    for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+    for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
 	scan_scsis(shpnt,0,0,0,0);           /* scan for scsi devices */
+	if (shpnt->select_queue_depths != NULL)
+	    (shpnt->select_queue_depths)(shpnt, scsi_devices);
+    }
 
     printk("scsi : detected ");
     for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
@@ -2480,11 +2555,13 @@
 int scsi_proc_info(char *buffer, char **start, off_t offset, int length, 
 		    int hostno, int inout)
 {
-    Scsi_Device *scd;
+    Scsi_Cmnd *SCpnt;
+    struct Scsi_Device_Template *SDTpnt;
+    Scsi_Device *scd, *scd_h = NULL;
     struct Scsi_Host *HBA_ptr;
-    int  parameter[4];
     char *p;
-    int	  i,size, len = 0;
+    int   host, channel, id, lun;
+    int	  size, len = 0;
     off_t begin = 0;
     off_t pos = 0;
 
@@ -2529,8 +2606,11 @@
 	return (len);     
     }
 
+    if(!buffer || length < 25 || strncmp("scsi", buffer, 4))
+	return(-EINVAL);
+
     /*
-     * Usage: echo "scsi singledevice 0 1 2 3" >/proc/scsi/scsi
+     * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
      * with  "0 1 2 3" replaced by your "Host Channel Id Lun".
      * Consider this feature BETA.
      *     CAUTION: This is not for hotplugging your peripherals. As
@@ -2540,35 +2620,106 @@
      * already connected device. It is perhaps not 
      * guaranteed this device doesn't corrupt an ongoing data transfer.
      */
-    if(!buffer || length < 25 || strncmp("scsi", buffer, 4))
-	return(-EINVAL);
-
-    if(!strncmp("singledevice", buffer + 5, 12)) {
-	p = buffer + 17;
+    if(!strncmp("add-single-device", buffer + 5, 17)) {
+	p = buffer + 23;
 
-	for(i=0; i<4; i++)	{
-	    p++;
-	    parameter[i] = simple_strtoul(p, &p, 0);
-	}
-	printk("scsi singledevice %d %d %d %d\n", parameter[0], parameter[1],
-			parameter[2], parameter[3]);
-
-	while(scd && (scd->host->host_no != parameter[0] 
-	      || scd->channel != parameter[1] 
-	      || scd->id != parameter[2] 
-	      || scd->lun != parameter[3])) {
+        host    = simple_strtoul(p, &p, 0);
+        channel = simple_strtoul(p+1, &p, 0);
+        id      = simple_strtoul(p+1, &p, 0);
+        lun     = simple_strtoul(p+1, &p, 0);
+
+	printk("scsi singledevice %d %d %d %d\n", host, channel,
+			id, lun);
+
+	while(scd && (scd->host->host_no != host 
+	      || scd->channel != channel 
+	      || scd->id != id 
+	      || scd->lun != lun)) {
 	    scd = scd->next;
 	}
 	if(scd)
 	    return(-ENOSYS);  /* We do not yet support unplugging */
-	while(HBA_ptr && HBA_ptr->host_no != parameter[0])
+	while(HBA_ptr && HBA_ptr->host_no != host)
 	    HBA_ptr = HBA_ptr->next;
 
 	if(!HBA_ptr)
 	    return(-ENXIO);
 
-	scan_scsis (HBA_ptr, 1, parameter[1], parameter[2], parameter[3]);
+	scan_scsis (HBA_ptr, 1, channel, id, lun);
 	return(length);
+        
+    } 
+
+    /*
+     * Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi
+     * with  "0 1 2 3" replaced by your "Host Channel Id Lun".
+     *
+     * Consider this feature pre-BETA.
+     *
+     *     CAUTION: This is not for hotplugging your peripherals. As
+     *     SCSI was not designed for this you could damage your
+     *     hardware and thoroughly confuse the SCSI subsystem.  
+     *
+     */
+    else if(!strncmp("remove-single-device", buffer + 5, 20)) {
+        p = buffer + 26;
+        
+        host    = simple_strtoul(p, &p, 0);
+        channel = simple_strtoul(p+1, &p, 0);
+        id      = simple_strtoul(p+1, &p, 0);
+        lun     = simple_strtoul(p+1, &p, 0);
+        
+        while(scd != NULL) {
+            if(scd->host->host_no == host  
+               && scd->channel == channel 
+               && scd->id == id 
+               && scd->lun == lun){
+                break;                
+            }
+            scd_h = scd;
+            scd = scd->next;
+        }
+        
+        if(scd == NULL)
+            return(-ENODEV);  /* there is no such device attached */
+        
+        if(scd->access_count)
+            return(-EBUSY);
+        
+        SDTpnt = scsi_devicelist;
+        while(SDTpnt != NULL) {
+            if(SDTpnt->detach) (*SDTpnt->detach)(scd);
+            SDTpnt = SDTpnt->next;
+        }
+        
+        if(scd->attached == 0) {
+            /*
+             * Nobody is using this device any more.
+             * Free all of the command structures.
+             */
+            for(SCpnt=scd->host->host_queue; SCpnt; SCpnt = SCpnt->next){
+                if(SCpnt->device == scd) {
+                    if(SCpnt->prev != NULL)
+                        SCpnt->prev->next = SCpnt->next;
+                    if(SCpnt->next != NULL)
+                        SCpnt->next->prev = SCpnt->prev;
+                    if(SCpnt == scd->host->host_queue)
+                        scd->host->host_queue = SCpnt->next;
+                    scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
+                }
+            }
+            /* Now we can remove the device structure */
+            if(scd_h != NULL) {
+                scd_h->next = scd->next;
+            } else if (scsi_devices == scd) {
+                /* We had a hit on the first entry of the device list */
+                scsi_devices = scd->next;
+            } 
+            scsi_init_free((char *) scd, sizeof(Scsi_Device));
+        } else {
+            return(-EBUSY);
+        }
+        return(0);
     }
     return(-EINVAL);
 }
@@ -2628,17 +2779,17 @@
     
     for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
 	host = SDpnt->host;
-	
+
 	if(SDpnt->type != TYPE_TAPE)
 	    new_dma_sectors += ((host->sg_tablesize *
 	                         sizeof(struct scatterlist) + 511) >> 9) *
-	                             host->cmd_per_lun;
+	                       SDpnt->queue_depth;
 	
 	if(host->unchecked_isa_dma &&
 	   scsi_need_isa_bounce_buffers &&
 	   SDpnt->type != TYPE_TAPE) {
 	    new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
-	        host->cmd_per_lun;
+						  SDpnt->queue_depth;
 	    new_need_isa_buffer++;
 	}
     }
diff -u --recursive --new-file v1.3.88/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v1.3.88/linux/drivers/scsi/scsi.h	Wed Mar 27 08:19:28 1996
+++ linux/drivers/scsi/scsi.h	Sun Apr 14 11:19:17 1996
@@ -163,6 +163,7 @@
     struct Scsi_Host * host;
     void (*scsi_request_fn)(void);  /* Used to jumpstart things after an 
 				     * ioctl */
+    struct scsi_cmnd *device_queue; /* queue of SCSI Command structures */
     void *hostdata;                 /* available to low-level driver */
     char type;
     char scsi_level;
@@ -170,6 +171,7 @@
     unsigned char current_tag;      /* current tag */
     unsigned char sync_min_period;  /* Not less than this period */
     unsigned char sync_max_offset;  /* Not greater than this offset */
+    unsigned char queue_depth;	    /* How deep a queue to use */
 
     unsigned writeable:1;
     unsigned removable:1; 
@@ -186,11 +188,12 @@
     unsigned soft_reset:1;          /* Uses soft reset option */
     unsigned sync:1;                /* Negotiate for sync transfers */
     unsigned single_lun:1;          /* Indicates we should only allow I/O to
-                                       one of the luns for the device at a time. */
-    unsigned was_reset:1;	/* There was a bus reset on the bus for this
-                                   device */
-    unsigned expecting_cc_ua:1;    /* Expecting a CHECK_CONDITION/UNIT_ATTN
-                                      because we did a bus reset. */
+                                     * one of the luns for the device at a 
+                                     * time. */
+    unsigned was_reset:1;           /* There was a bus reset on the bus for 
+                                     * this device */
+    unsigned expecting_cc_ua:1;     /* Expecting a CHECK_CONDITION/UNIT_ATTN
+                                     * because we did a bus reset. */
 } Scsi_Device;
 
 /*
@@ -304,8 +307,16 @@
  * should keep the command alive. */
 #define SCSI_RESET_WAKEUP 4
 
+/* The command is not active in the low level code. Command probably
+   finished. */
+#define SCSI_RESET_NOT_RUNNING 5
+
 /* Something went wrong, and we do not know how to fix it. */
-#define SCSI_RESET_ERROR 5
+#define SCSI_RESET_ERROR 6
+
+#define SCSI_RESET_SYNCHRONOUS		0x01
+#define SCSI_RESET_ASYNCHRONOUS		0x02
+#define SCSI_RESET_SUGGEST_BUS_RESET	0x04
 
 /*
  * This is a bitmask that is ored with one of the above codes.
@@ -347,7 +358,7 @@
     unsigned char target, lun, channel;
     unsigned char cmd_len;
     unsigned char old_cmd_len;
-    struct scsi_cmnd *next, *prev;  
+    struct scsi_cmnd *next, *prev, *device_next, *reset_chain;
     
     /* These elements define the operation we are about to perform */
     unsigned char cmnd[12];
@@ -378,6 +389,22 @@
 
     unsigned char sense_buffer[16];  /* Sense for this command, if needed */
 
+    /*
+      A SCSI Command is assigned a nonzero serial_number when internal_cmnd
+      passes it to the driver's queue command function.  The serial_number
+      is cleared when scsi_done is entered indicating that the command has
+      been completed.  If a timeout occurs, the serial number at the moment
+      of timeout is copied into serial_number_at_timeout.  By subseuqently
+      comparing the serial_number and serial_number_at_timeout fields
+      during abort or reset processing, we can detect whether the command
+      has already completed.  This also detects cases where the command has
+      completed and the SCSI Command structure has already being reused
+      for another command, so that we can avoid incorrectly aborting or
+      resetting the new command.
+    */
+
+    unsigned long serial_number;
+    unsigned long serial_number_at_timeout;
 
     int retries;
     int allowed;
@@ -428,7 +455,7 @@
  *  DID_ABORT is returned in the hostbyte.
  */
 
-extern int scsi_abort (Scsi_Cmnd *, int code, int pid);
+extern int scsi_abort (Scsi_Cmnd *, int code);
 
 extern void scsi_do_cmd (Scsi_Cmnd *, const void *cmnd ,
 			 void *buffer, unsigned bufflen, 
@@ -439,7 +466,7 @@
 extern Scsi_Cmnd * allocate_device(struct request **, Scsi_Device *, int);
 
 extern Scsi_Cmnd * request_queueable(struct request *, Scsi_Device *);
-extern int scsi_reset (Scsi_Cmnd *, int);
+extern int scsi_reset (Scsi_Cmnd *, unsigned int);
 
 extern int max_scsi_hosts;
 
diff -u --recursive --new-file v1.3.88/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v1.3.88/linux/drivers/scsi/sd.c	Fri Apr 12 15:52:01 1996
+++ linux/drivers/scsi/sd.c	Sun Apr 14 11:19:17 1996
@@ -56,8 +56,8 @@
  *  Time out in seconds for disks and Magneto-opticals (which are slower).
  */
 
-#define SD_TIMEOUT (7 * HZ)
-#define SD_MOD_TIMEOUT (8 * HZ)
+#define SD_TIMEOUT (15 * HZ)
+#define SD_MOD_TIMEOUT (15 * HZ)
 
 #define CLUSTERABLE_DEVICE(SC) (SC->host->use_clustering && \
 				SC->device->type != TYPE_MOD)
diff -u --recursive --new-file v1.3.88/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v1.3.88/linux/drivers/sound/soundcard.c	Fri Apr 12 15:52:03 1996
+++ linux/drivers/sound/soundcard.c	Sun Apr 14 10:56:06 1996
@@ -170,13 +170,13 @@
 
       len = _IOC_SIZE (cmd);
 
-      if (_IOC_DIR (cmd) == _IOC_WRITE)
+      if (_IOC_DIR (cmd) & _IOC_WRITE)
 	{
 	  if ((err = verify_area (VERIFY_READ, (void *) arg, len)) < 0)
 	    return err;
 	}
 
-      if (_IOC_DIR (cmd) == _IOC_READ)
+      if (_IOC_DIR (cmd) & _IOC_READ)
 	{
 	  if ((err = verify_area (VERIFY_WRITE, (void *) arg, len)) < 0)
 	    return err;
diff -u --recursive --new-file v1.3.88/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v1.3.88/linux/fs/binfmt_elf.c	Tue Mar 12 08:22:32 1996
+++ linux/fs/binfmt_elf.c	Sun Apr 14 11:14:43 1996
@@ -964,16 +964,17 @@
 	segs = 0;
 	size = 0;
 	for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
-		int sz = vma->vm_end-vma->vm_start;
+		if (maydump(vma))
+		{
+			int sz = vma->vm_end-vma->vm_start;
 		
-		if (!maydump(vma))
-			continue;
-
-		if (size+sz > limit)
-			break;
+			if (size+sz >= limit)
+				break;
+			else
+				size += sz;
+		}
 		
 		segs++;
-		size += sz;
 	}
 #ifdef DEBUG
 	printk("elf_core_dump: %d segs taking %d bytes\n", segs, size);
@@ -1152,8 +1153,6 @@
 		struct elf_phdr phdr;
 		size_t sz;
 
-		if (!maydump(vma))
-			continue;
 		i++;
 
 		sz = vma->vm_end - vma->vm_start;
@@ -1162,9 +1161,9 @@
 		phdr.p_offset = offset;
 		phdr.p_vaddr = vma->vm_start;
 		phdr.p_paddr = 0;
-		phdr.p_filesz = sz;
+		phdr.p_filesz = maydump(vma) ? sz : 0;
 		phdr.p_memsz = sz;
-		offset += sz;
+		offset += phdr.p_filesz;
 		phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
 		if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W;
 		if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X;
diff -u --recursive --new-file v1.3.88/linux/fs/buffer.c linux/fs/buffer.c
--- v1.3.88/linux/fs/buffer.c	Fri Apr 12 15:52:04 1996
+++ linux/fs/buffer.c	Sun Apr 14 10:24:33 1996
@@ -1818,9 +1818,11 @@
 
 static void wakeup_bdflush(int wait)
 {
-	run_task_queue(&tq_disk);
 	wake_up(&bdflush_wait);
-	if(wait) sleep_on(&bdflush_done);
+	if (wait) {
+		run_task_queue(&tq_disk);
+		sleep_on(&bdflush_done);
+	}
 }
 
 
diff -u --recursive --new-file v1.3.88/linux/fs/isofs/rock.c linux/fs/isofs/rock.c
--- v1.3.88/linux/fs/isofs/rock.c	Sat Apr 13 18:22:07 1996
+++ linux/fs/isofs/rock.c	Mon Apr 15 08:30:06 1996
@@ -507,6 +507,7 @@
 	 if(slen < 2) break;
 	 if(!rootflag) strcat(rpnt,"/");
        };
+       break;
      case SIG('C','E'):
        CHECK_CE; /* This tells is if there is a continuation record */
        break;
diff -u --recursive --new-file v1.3.88/linux/fs/locks.c linux/fs/locks.c
--- v1.3.88/linux/fs/locks.c	Wed Apr 10 17:02:25 1996
+++ linux/fs/locks.c	Sun Apr 14 14:48:53 1996
@@ -861,26 +861,29 @@
 static void locks_delete_lock(struct file_lock **fl_p, unsigned int wait)
 {
 	struct file_lock *fl;
-	struct file_lock *bfl;
+	struct file_lock *pfl;
+	struct file_lock *nfl;
 	
 	fl = *fl_p;
-	*fl_p = (*fl_p)->fl_next;
+	*fl_p = fl->fl_next;
+	pfl = fl->fl_prevlink;
+	nfl = fl->fl_nextlink;
 
-	if (fl->fl_nextlink != NULL)
-		fl->fl_nextlink->fl_prevlink = fl->fl_prevlink;
+	if (nfl != NULL)
+		nfl->fl_prevlink = pfl;
 
-	if (fl->fl_prevlink != NULL)
-		fl->fl_prevlink->fl_nextlink = fl->fl_nextlink;
+	if (pfl != NULL)
+		pfl->fl_nextlink = nfl;
 	else {
-		file_lock_table = fl->fl_nextlink;
+		file_lock_table = nfl;
 	}
 	
-	while ((bfl = fl->fl_block) != NULL) {
-		fl->fl_block = bfl->fl_block;
-		bfl->fl_block = NULL;
-		wake_up(&bfl->fl_wait);
+	while ((nfl = fl->fl_block) != NULL) {
+		fl->fl_block = nfl->fl_block;
+		nfl->fl_block = NULL;
+		wake_up(&nfl->fl_wait);
 		if (wait)
-			sleep_on(&bfl->fl_wait);
+			sleep_on(&nfl->fl_wait);
 	}
 
 	wake_up(&fl->fl_wait);
diff -u --recursive --new-file v1.3.88/linux/fs/namei.c linux/fs/namei.c
--- v1.3.88/linux/fs/namei.c	Wed Apr 10 17:02:25 1996
+++ linux/fs/namei.c	Sun Apr 14 14:48:53 1996
@@ -388,7 +388,8 @@
 	/* SunOS, Solaris 2.x and HPUX all deny open() on
 	 * an existing file with mandatory locks.
 	 */
-	if ((error = locks_verify_locked(inode)) != 0) {
+	error = locks_verify_locked(inode);
+	if (error) {
 		iput(inode);
 		return error;
 	}
@@ -443,7 +444,8 @@
 		 * here. Only O_TRUNC calls can modify the file contents -
 		 * but none of the commercial OS'es seem to do it this way.
 		 */
-		if ((error = locks_verify_locked(inode)) != 0) {
+		error = locks_verify_locked(inode);
+		if (error) {
 			iput(inode);
 			return error;
 		}
diff -u --recursive --new-file v1.3.88/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v1.3.88/linux/fs/nfs/inode.c	Fri Apr 12 15:52:04 1996
+++ linux/fs/nfs/inode.c	Mon Apr 15 08:07:36 1996
@@ -25,6 +25,7 @@
 #include <linux/errno.h>
 #include <linux/locks.h>
 #include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/segment.h>
diff -u --recursive --new-file v1.3.88/linux/fs/proc/array.c linux/fs/proc/array.c
--- v1.3.88/linux/fs/proc/array.c	Mon Apr  8 19:01:45 1996
+++ linux/fs/proc/array.c	Mon Apr 15 10:03:26 1996
@@ -959,6 +959,7 @@
 extern int get_cpuinfo(char *);
 extern int get_pci_list(char*);
 extern int get_md_status (char *);
+extern int get_rtc_status (char *);
 #ifdef __SMP_PROF__
 extern int get_smp_prof_list(char *);
 #endif
@@ -1029,6 +1030,10 @@
 
                 case PROC_MTAB:
                        return get_filesystem_info( page );
+#ifdef CONFIG_RTC
+		case PROC_RTC:
+			return get_rtc_status(page);
+#endif
 	}
 	return -EBADF;
 }
diff -u --recursive --new-file v1.3.88/linux/fs/proc/root.c linux/fs/proc/root.c
--- v1.3.88/linux/fs/proc/root.c	Mon Apr  8 19:01:45 1996
+++ linux/fs/proc/root.c	Mon Apr 15 10:03:26 1996
@@ -352,6 +352,12 @@
 		PROC_CMDLINE, 7, "cmdline",
 		S_IFREG | S_IRUGO, 1, 0, 0,
 	});
+#ifdef CONFIG_RTC
+	proc_register(&proc_root, &(struct proc_dir_entry) {
+		PROC_RTC, 3, "rtc",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+	});
+#endif
 
 	proc_register( &proc_root, &(struct proc_dir_entry)
 	   { PROC_MTAB, 6, "mounts", S_IFREG | S_IRUGO, 1, 0, 0, } );
diff -u --recursive --new-file v1.3.88/linux/fs/super.c linux/fs/super.c
--- v1.3.88/linux/fs/super.c	Wed Apr 10 17:02:25 1996
+++ linux/fs/super.c	Sun Apr 14 11:47:25 1996
@@ -8,6 +8,9 @@
  *                                   - mount systemcall
  *                                   - umount systemcall
  *
+ *  Added options to /proc/mounts
+ *  Torbjörn Lindh (torbjorn.lindh@gopta.se), April 14, 1996.
+ *
  * GK 2/5/95  -  Changed to support mounting the root fs via NFS
  *
  *  Added kerneld support: Jacques Gelinas and Bjorn Ekwall
@@ -36,9 +39,9 @@
 #include <linux/kerneld.h>
 #endif
  
-#ifdef CONFIG_ROOT_NFS
 #include <linux/nfs_fs.h>
-#endif
+#include <linux/nfs_fs_sb.h>
+#include <linux/nfs_mount.h>
 
 extern void wait_for_keypress(void);
 extern struct file_operations * get_blkfops(unsigned int major);
@@ -263,16 +266,94 @@
 	return retval;
 }
 
+static struct proc_fs_info {
+	int flag;
+	char *str;
+} fs_info[] = {
+	{ MS_NOEXEC, ",noexec" },
+	{ MS_NOSUID, ",nosuid" },
+	{ MS_NODEV, ",nodev" },
+	{ MS_SYNCHRONOUS, ",sync" },
+#ifdef MS_NOSUB			/* Can't find this except in mount.c */
+	{ MS_NOSUB, ",nosub" },
+#endif
+	{ 0, NULL }
+};
+
+static struct proc_nfs_info {
+	int flag;
+	char *str;
+} nfs_info[] = {
+	{ NFS_MOUNT_SOFT, ",soft" },
+	{ NFS_MOUNT_INTR, ",intr" },
+	{ NFS_MOUNT_POSIX, ",posix" },
+	{ NFS_MOUNT_NOCTO, ",nocto" },
+	{ NFS_MOUNT_NOAC, ",noac" },
+	{ 0, NULL }
+};
+
 int get_filesystem_info( char *buf )
 {
 	struct vfsmount *tmp = vfsmntlist;
+	struct proc_fs_info *fs_infop;
+	struct proc_nfs_info *nfs_infop;
+	struct nfs_server *nfss;
 	int len = 0;
 
-	while ( tmp && len < PAGE_SIZE - 80 )
+	while ( tmp && len < PAGE_SIZE - 160)
 	{
 		len += sprintf( buf + len, "%s %s %s %s",
 			tmp->mnt_devname, tmp->mnt_dirname, tmp->mnt_sb->s_type->name,
 			tmp->mnt_flags & MS_RDONLY ? "ro" : "rw" );
+		for (fs_infop = fs_info; fs_infop->flag; fs_infop++) {
+		  if (tmp->mnt_flags & fs_infop->flag) {
+		    strcpy(buf + len, fs_infop->str);
+		    len += strlen(fs_infop->str);
+		  }
+		}
+		if (!strcmp("nfs", tmp->mnt_sb->s_type->name)) {
+			nfss = &tmp->mnt_sb->u.nfs_sb.s_server;
+			if (nfss->rsize != NFS_DEF_FILE_IO_BUFFER_SIZE) {
+				len += sprintf(buf+len, ",rsize=%d",
+					       nfss->rsize);
+			}
+			if (nfss->wsize != NFS_DEF_FILE_IO_BUFFER_SIZE) {
+				len += sprintf(buf+len, ",wsize=%d",
+					       nfss->wsize);
+			}
+			if (nfss->timeo != 7*HZ/10) {
+				len += sprintf(buf+len, ",timeo=%d",
+					       nfss->timeo*10/HZ);
+			}
+			if (nfss->retrans != 3) {
+				len += sprintf(buf+len, ",retrans=%d",
+					       nfss->retrans);
+			}
+			if (nfss->acregmin != 3*HZ) {
+				len += sprintf(buf+len, ",acregmin=%d",
+					       nfss->acregmin/HZ);
+			}
+			if (nfss->acregmax != 60*HZ) {
+				len += sprintf(buf+len, ",acregmax=%d",
+					       nfss->acregmax/HZ);
+			}
+			if (nfss->acdirmin != 30*HZ) {
+				len += sprintf(buf+len, ",acdirmin=%d",
+					       nfss->acdirmin/HZ);
+			}
+			if (nfss->acdirmax != 60*HZ) {
+				len += sprintf(buf+len, ",acdirmax=%d",
+					       nfss->acdirmax/HZ);
+			}
+			for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
+				if (nfss->flags & nfs_infop->flag) {
+					strcpy(buf + len, nfs_infop->str);
+					len += strlen(nfs_infop->str);
+				}
+			}
+			len += sprintf(buf+len, ",addr=%s",
+				       nfss->hostname);
+		}
 		len += sprintf( buf + len, " 0 0\n" );
 		tmp = tmp->mnt_next;
 	}
diff -u --recursive --new-file v1.3.88/linux/include/linux/config.h linux/include/linux/config.h
--- v1.3.88/linux/include/linux/config.h	Mon Mar 25 10:03:24 1996
+++ linux/include/linux/config.h	Mon Apr 15 10:05:08 1996
@@ -27,7 +27,7 @@
  * in linux/version.h, and should only be used by linux/version.c
  */
 
-/* Don't touch these, unless you really know what your doing. */
+/* Don't touch these, unless you really know what you're doing. */
 #define DEF_INITSEG	0x9000
 #define DEF_SYSSEG	0x1000
 #define DEF_SETUPSEG	0x9020
diff -u --recursive --new-file v1.3.88/linux/include/linux/fs.h linux/include/linux/fs.h
--- v1.3.88/linux/include/linux/fs.h	Fri Apr 12 15:52:07 1996
+++ linux/include/linux/fs.h	Mon Apr 15 10:05:08 1996
@@ -320,7 +320,7 @@
 	loff_t f_pos;
 	unsigned short f_flags;
 	unsigned short f_count;
-	unsigned long f_reada, f_ramax, f_rapos, f_ralen;
+	unsigned long f_reada, f_ramax, f_rapos, f_ralen, f_rawin;
 	struct file *f_next, *f_prev;
 	int f_owner;		/* pid or -pgrp where SIGIO should be sent */
 	struct inode * f_inode;
diff -u --recursive --new-file v1.3.88/linux/include/linux/if_frad.h linux/include/linux/if_frad.h
--- v1.3.88/linux/include/linux/if_frad.h	Fri Apr 12 15:52:07 1996
+++ linux/include/linux/if_frad.h	Mon Apr 15 12:06:49 1996
@@ -10,6 +10,11 @@
  *
  * Author:	Mike McLagan <mike.mclagan@linux.org>
  *
+ * Changes:
+ *		0.15	Mike McLagan	changed structure defs (packed)
+ *					re-arranged flags
+ *					added DLCI_RET vars
+ *
  *		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
diff -u --recursive --new-file v1.3.88/linux/include/linux/mc146818rtc.h linux/include/linux/mc146818rtc.h
--- v1.3.88/linux/include/linux/mc146818rtc.h	Sun Oct  1 20:35:53 1995
+++ linux/include/linux/mc146818rtc.h	Mon Apr 15 10:03:26 1996
@@ -106,4 +106,22 @@
 #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
 #endif
 
+/*
+ * ioctl calls that are permitted to the /dev/rtc interface, if 
+ * CONFIG_RTC was enabled.
+ */
+
+#define RTC_AIE_ON	0x01		/* Alarm int. enable on		*/
+#define RTC_AIE_OFF	0x02		/* ... off			*/
+#define RTC_UIE_ON	0x03		/* Update int. enable on	*/
+#define RTC_UIE_OFF	0x04		/* ... off			*/
+#define RTC_PIE_ON	0x05		/* Periodic int. enable on	*/
+#define RTC_PIE_OFF	0x06		/* ... off			*/
+#define RTC_ALM_SET	0x07		/* Set alarm (struct tm)	*/
+#define RTC_ALM_READ	0x08		/* Read alarm (struct tm)	*/
+#define RTC_RD_TIME	0x09		/* Read RTC time (struct tm)	*/
+#define RTC_SET_TIME	0x0a		/* Set time of RTC (not used)	*/
+#define RTC_IRQP_READ	0x0b		/* Read periodic IRQ rate (Hz)	*/
+#define RTC_IRQP_SET	0x0c		/* Set periodic IRQ rate (Hz)	*/
+
 #endif /* _MC146818RTC_H */
diff -u --recursive --new-file v1.3.88/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v1.3.88/linux/include/linux/proc_fs.h	Fri Apr 12 15:52:08 1996
+++ linux/include/linux/proc_fs.h	Mon Apr 15 10:05:12 1996
@@ -41,7 +41,8 @@
 	PROC_CMDLINE,
 	PROC_SYS,
 	PROC_MTAB,
-	PROC_MD
+	PROC_MD,
+	PROC_RTC
 };
 
 enum pid_directory_inos {
diff -u --recursive --new-file v1.3.88/linux/include/linux/sdla.h linux/include/linux/sdla.h
--- v1.3.88/linux/include/linux/sdla.h	Fri Apr 12 15:52:08 1996
+++ linux/include/linux/sdla.h	Mon Apr 15 11:50:47 1996
@@ -5,10 +5,15 @@
  *
  *		Global definitions for the Frame relay interface.
  *
- * Version:	@(#)if_ifrad.h	0.15	31 Mar 96
+ * Version:	@(#)if_ifrad.h	0.20	13 Apr 96
  *
  * Author:	Mike McLagan <mike.mclagan@linux.org>
  *
+ * Changes:
+ *		0.15	Mike McLagan	Structure packing
+ *
+ *		0.20	Mike McLagan	New flags for S508 buffer handling
+ *
  *		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
@@ -216,6 +221,11 @@
 
 /* Configuration flags */
 #define SDLA_DIRECT_RECV		0x0080
+#define SDLA_TX_NO_EXCEPT		0x0020
+#define SDLA_NO_ICF_MSGS		0x1000
+#define SDLA_TX50_RX50			0x0000
+#define SDLA_TX70_RX30			0x2000
+#define SDLA_TX30_RX70			0x4000
 
 /* IRQ selection flags */
 #define SDLA_IRQ_RECEIVE		0x01
diff -u --recursive --new-file v1.3.88/linux/mm/filemap.c linux/mm/filemap.c
--- v1.3.88/linux/mm/filemap.c	Sat Apr 13 18:22:07 1996
+++ linux/mm/filemap.c	Sun Apr 14 09:55:50 1996
@@ -27,6 +27,10 @@
 #include <asm/system.h>
 #include <asm/pgtable.h>
 
+#if 0
+#define DEBUG_ASYNC_AHEAD
+#endif
+
 /*
  * Shared mappings implemented 30.11.1994. It's not fully working yet,
  * though.
@@ -322,6 +326,8 @@
 	unsigned long rapos, ppos;
 
 	ppos = pos & PAGE_MASK;
+	rapos = filp->f_rapos & PAGE_MASK;
+	max_ahead = 0;
 /*
  * If the current page is locked, try some synchronous read-ahead in order
  * to avoid too small IO requests.
@@ -329,56 +335,47 @@
 	if (PageLocked(page)) {
 		max_ahead = filp->f_ramax;
 		rapos = ppos;
-/*		try_async = 1  */ /* Seems questionable */
+		filp->f_rawin = 0;
+		filp->f_ralen = PAGE_SIZE;
 	}
 /*
  * The current page is not locked
  * It may be the moment to try asynchronous read-ahead.
- */
-	else {
-/*
- * Compute the position of the last page we have tried to read
- */
-		rapos = filp->f_rapos & PAGE_MASK;
-		if (rapos) rapos -= PAGE_SIZE;
-/*
- * If asynchronous is the good tactics and if the current position is
- * inside the previous read-ahead window,
- * check the last red page:
- * - if locked, previous IO request is probably not complete, and we will
- *    not try to do another IO request.
- * - if not locked, previous IO request is probably complete, and it is the
- *    good moment to try a new asynchronous read-ahead request.
+ * If asynchronous is the suggested tactics and if the current position is
+ * inside the previous read-ahead window, check the last read page:
+ * - if locked, the previous IO request is probably not complete, and
+ *   we will not try to do another IO request.
+ * - if not locked, the previous IO request is probably complete, and
+ *   this is a good moment to try a new asynchronous read-ahead request.
  * try_async = 2 means that we have to force unplug of the device in
  * order to force call to the strategy routine of the disk driver and 
  * start IO asynchronously.
  */
-		if (try_async == 1 && pos <= filp->f_rapos &&
-			 pos + filp->f_ralen >= filp->f_rapos) {
-			struct page *a_page;
+	else if (try_async == 1 && rapos >= PAGE_SIZE &&
+	         ppos <= rapos && ppos + filp->f_ralen >= rapos) {
+		struct page *a_page;
 /*
  * Add ONE page to max_ahead in order to try to have the same IO max size as
  * synchronous read-ahead (MAX_READAHEAD + 1)*PAGE_SIZE.
+ * Compute the position of the last page we have tried to read.
  */
-			max_ahead = filp->f_ramax + PAGE_SIZE;
+		max_ahead = filp->f_ramax + PAGE_SIZE;
+		rapos -= PAGE_SIZE;
 
-			if (rapos < inode->i_size) {
-				a_page = find_page(inode, rapos);
-				if (a_page) {
-					if (PageLocked(a_page))
-						max_ahead = 0;
-					a_page->count--;
-				}
+		if (rapos < inode->i_size) {
+			a_page = find_page(inode, rapos);
+			if (a_page) {
+				if (PageLocked(a_page))
+					max_ahead = 0;
+				a_page->count--;
 			}
-			else
-				max_ahead = 0;
-			try_async = 2;
 		}
-		else {
-			max_ahead = 0;
+		if (max_ahead) {
+			filp->f_rawin = filp->f_ralen;
+			filp->f_ralen = 0;
+			try_async = 2;
 		}
 	}
-
 /*
  * Try to read pages.
  * We hope that ll_rw_blk() plug/unplug, coalescence and sort will work fine
@@ -391,27 +388,22 @@
 	}
 /*
  * If we tried to read some pages,
+ * Compute the new read-ahead position.
+ * It is the position of the next byte.
  * Store the length of the current read-ahead window.
  * If necessary,
  *    Try to force unplug of the device in order to start an asynchronous
  *    read IO.
  */
-	if (ahead > 0) {
-		filp->f_ralen = ahead;
+	if (ahead) {
+		filp->f_ralen += ahead;
+		filp->f_rawin += filp->f_ralen;
+		filp->f_rapos = rapos + ahead + PAGE_SIZE;
 		if (try_async == 2) {
-/*
- * Schedule() should be changed to run_task_queue(...)
- */
 			run_task_queue(&tq_disk);
-			try_async = 1;
 		}
 	}
 /*
- * Compute the new read-ahead position.
- * It is the position of the next byte.
- */
-	filp->f_rapos = rapos + ahead + PAGE_SIZE;
-/*
  * Wait on the page if necessary
  */
 	if (PageLocked(page)) {
@@ -424,78 +416,87 @@
 int generic_file_read(struct inode * inode, struct file * filp, char * buf, int count)
 {
 	int error, read;
-	unsigned long pos, page_cache;
+	unsigned long pos, ppos, page_cache;
 	int try_async;
+
+#ifdef DEBUG_ASYNC_AHEAD
+static long ccount = 0;
+if (count > 0) ccount += count;
+#endif
 	
 	if (count <= 0)
 		return 0;
+
 	error = 0;
 	read = 0;
 	page_cache = 0;
 
 	pos = filp->f_pos;
+	ppos = pos & PAGE_MASK;
 /*
- * Dont believe f_reada
- * --------------------
- * f_reada is set to 0 by seek operations.
- * If we believe f_reada, small seek ops break asynchronous read-ahead.
- * That may be quite bad for small seeks or rewrites operations.
- * I prefer to check if the current position is inside the previous read-ahead
- * window.
+ * Check if the current position is inside the previous read-ahead window.
  * If that's true, I assume that the file accesses are sequential enough to
  * continue asynchronous read-ahead.
+ * Do minimum read-ahead at the beginning of the file since some tools
+ * only read the beginning of files.
+ * Break read-ahead if the file position is outside the previous read ahead
+ * window or if read-ahead position is 0.
  */
-	if (pos <= filp->f_rapos && pos + filp->f_ralen >= filp->f_rapos) {
-		filp->f_reada = 1;
-	}
 /*
- * Do minimum read-ahead at the beginning of the file.
- * Some tools only read the start of the file only.
- * Break read-ahead if the file position is after the previous read ahead
- * position or if read-ahead position is 0.
+ * Will not try asynchronous read-ahead.
+ * Reset to zero, read-ahead context.
  */
-	else if (pos+count < MIN_READAHEAD || !filp->f_rapos ||
-	         pos > filp->f_rapos) {
-		filp->f_reada = 0;
-	}
-
+	if (pos+count < MIN_READAHEAD || !filp->f_rapos ||
+	    ppos > filp->f_rapos || ppos + filp->f_rawin < filp->f_rapos) {
+		try_async = 0;
+#ifdef DEBUG_ASYNC_AHEAD
+		if (ccount > 10000000) {
+			ccount = 0;
+			printk("XXXXXXXX ppos=%ld rapos=%ld ralen=%ld ramax=%ld rawin=%ld\n",
+				ppos, filp->f_rapos, filp->f_ralen, filp->f_ramax, filp->f_rawin);
+		}
+#endif
+		filp->f_rapos = 0;
+		filp->f_ralen = 0;
+		filp->f_ramax = 0;
+		filp->f_rawin = 0;
 /*
- * Now f_reada = 1 means that asynchronous read-ahead is the good tactics.
- * Will try asynchronous read-ahead as soon as possible.
+ * Will try asynchronous read-ahead.
  * Double the max read ahead size each time.
  *   That heuristic avoid to do some large IO for files that are not really
- *   accessed sequentially.
+ *   accessed sequentialy.
  */
-	if (filp->f_reada) {
+	} else {
 		try_async = 1;
+#ifdef DEBUG_ASYNC_AHEAD
+		if (ccount > 10000000) {
+			ccount = 0;
+			printk("XXXXXXXX ppos=%ld rapos=%ld ralen=%ld ramax=%ld rawin=%ld\n",
+				ppos, filp->f_rapos, filp->f_ralen, filp->f_ramax, filp->f_rawin);
+		}
+#endif
 		filp->f_ramax += filp->f_ramax;
 	}
 /*
- * f_reada = 0 means that asynchronous read_ahead is quite bad.
- * Will not try asynchronous read-ahead first.
- * Reset to zero, read-ahead context.
+ * Compute a good value for read-ahead max
+ * If the read operation stay in the first half page, force no readahead.
+ * Else try first some value near count.
+ *      do at least MIN_READAHEAD and at most MAX_READAHEAD.
+ * (Should be a little reworked)
  */
-	else {
+	if (pos + count <= (PAGE_SIZE >> 1)) {
 		try_async = 0;
-		filp->f_rapos = 0;
-		filp->f_ralen = 0;
 		filp->f_ramax = 0;
+	} else {
+		if (filp->f_ramax < count)
+			filp->f_ramax = count & PAGE_MASK;
+
+		if (filp->f_ramax < MIN_READAHEAD)
+			filp->f_ramax = MIN_READAHEAD;
+		else if (filp->f_ramax > MAX_READAHEAD)
+			filp->f_ramax = MAX_READAHEAD;
 	}
 
-/*
- * Compute a good value for read-ahead max
- * Try first some value near count.
- * Do at least MIN_READAHEAD and at most MAX_READAHEAD.
- * (Should be a little reworked)
- */
-	if (filp->f_ramax < count)
-		filp->f_ramax = count & PAGE_MASK;
-
-	if (filp->f_ramax < MIN_READAHEAD)
-		filp->f_ramax = MIN_READAHEAD;
-	else if (filp->f_ramax > MAX_READAHEAD)
-		filp->f_ramax = MAX_READAHEAD;
-
 	for (;;) {
 		struct page *page;
 		unsigned long offset, addr, nr;
@@ -537,8 +538,19 @@
 		addr = page_address(page);
 		if (nr > count)
 			nr = count;
-
-		page_cache = generic_file_readahead(filp, inode, try_async, pos, page, page_cache);
+/*
+ * Do not try to readahead if the current page is not filled or being filled.
+ * If our goal was to try asynchronous read-ahead, we were quite wrong.
+ * Set max readahead to some shorter value in order to fix a little
+ * this mistake.
+ */
+		if (PageUptodate(page) || PageLocked(page))
+			page_cache = generic_file_readahead(filp, inode, try_async, pos, page, page_cache);
+		else if (try_async) {
+			filp->f_ramax = (filp->f_ramax / 2) & PAGE_MASK;
+			if (filp->f_ramax < MIN_READAHEAD)
+				filp->f_ramax = MIN_READAHEAD;
+		}
 
 		if (!PageUptodate(page))
 			goto read_page;
diff -u --recursive --new-file v1.3.88/linux/mm/memory.c linux/mm/memory.c
--- v1.3.88/linux/mm/memory.c	Fri Apr 12 15:52:10 1996
+++ linux/mm/memory.c	Sat Apr 13 18:17:19 1996
@@ -742,7 +742,7 @@
 check_stack:
 	if (!(vma->vm_flags & VM_GROWSDOWN))
 		goto bad_area;
-	if (expand_stack(vma, start))
+	if (expand_stack(vma, start) == 0)
 		goto good_area;
 
 bad_area:
diff -u --recursive --new-file v1.3.88/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v1.3.88/linux/net/ipv4/tcp_input.c	Sat Apr 13 18:22:08 1996
+++ linux/net/ipv4/tcp_input.c	Mon Apr 15 08:30:06 1996
@@ -705,10 +705,11 @@
 	 *	right hand window edge of the host.
 	 *	We do a bit of work here to track number of times we've
 	 *	seen this ack without a change in the right edge of the
-	 *	window. This will allow us to do fast retransmits.
+	 *	window and no data in the packet.
+	 *	This will allow us to do fast retransmits.
 	 */
 
-	if (sk->rcv_ack_seq == ack && sk->window_seq == window_seq)
+	if (sk->rcv_ack_seq == ack && sk->window_seq == window_seq && !(flag&1))
 	{
 		/*
 		 * We only want to short cut this once, many
@@ -1318,8 +1319,7 @@
 		    if(sk->debug)
 			    printk("Ack past end of seq packet.\n");
 		    tcp_send_ack(sk);
-		    sk->ack_backlog++;
-		    tcp_reset_xmit_timer(sk, TIME_WRITE, min(sk->ato, HZ/2));
+		    tcp_send_delayed_ack(sk,HZ/2);
 	    }
 	}
 }
diff -u --recursive --new-file v1.3.88/linux/scripts/Makefile linux/scripts/Makefile
--- v1.3.88/linux/scripts/Makefile	Mon Apr  8 19:01:48 1996
+++ linux/scripts/Makefile	Mon Apr 15 08:30:38 1996
@@ -35,6 +35,6 @@
 	$(HOSTCC) $(HOSTCFLAGS) -c -o tkgen.o tkgen.c
 
 clean:
-	rm -f kconfig.tk *.o parse
+	rm -f *~ kconfig.tk *.o tkparse
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.88/linux/scripts/tkgen.c linux/scripts/tkgen.c
--- v1.3.88/linux/scripts/tkgen.c	Mon Apr  8 19:01:48 1996
+++ linux/scripts/tkgen.c	Mon Apr 15 08:30:06 1996
@@ -46,6 +46,10 @@
  *                  (Apparently there still are some out there!)
  *                - Tabstops seem sensible now.
  *
+ * 1996 04 14
+ * Avery Pennarun - Reduced flicker when creating windows, even with "update
+ *                  idletasks" hack.
+ *
  * TO DO:
  *   - clean up - there are useless ifdef's everywhere.
  *   - better comments throughout - C code generating tcl is really cryptic.
@@ -93,6 +97,7 @@
   printf("proc menu%d {w title} {\n", menu_num);
   printf("\tcatch {destroy $w}\n");
   printf("\ttoplevel $w -class Dialog\n");
+  printf("\twm withdraw $w\n");
   printf("\tmessage $w.m -width 400 -aspect 300 -text \\\n");
   printf("\t\t\"%s\"  -relief raised\n",label);
   printf("\tpack $w.m -pady 10 -side top -padx 10\n");
@@ -546,7 +551,8 @@
   printf("\tupdate idletasks\n");
   printf("\twm maxsize $w [winfo width $w] [winfo screenheight $w]\n");
   printf("\twm minsize $w [winfo width $w] 100\n\n");
-  
+  printf("\twm deiconify $w\n");
+    
   printf("}\n\n\n");
 
   /*
