]> git.neil.brown.name Git - history.git/commitdiff
Import 1.3.89 1.3.89
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:49 +0000 (15:10 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:49 +0000 (15:10 -0500)
57 files changed:
CREDITS
Documentation/Changes
Documentation/Configure.help
Documentation/rtc.txt [new file with mode: 0644]
Documentation/svga.txt
MAINTAINERS
Makefile
arch/alpha/defconfig
arch/alpha/mm/init.c
arch/i386/boot/video.S
arch/i386/defconfig
arch/i386/kernel/setup.c
drivers/block/ide.c
drivers/block/ll_rw_blk.c
drivers/char/Config.in
drivers/char/Makefile
drivers/char/mem.c
drivers/char/misc.c
drivers/char/rtc.c [new file with mode: 0644]
drivers/net/dlci.c
drivers/net/sdla.c
drivers/net/tulip.c
drivers/net/wic.c
drivers/scsi/BusLogic.c
drivers/scsi/BusLogic.h
drivers/scsi/ChangeLog
drivers/scsi/README.BusLogic
drivers/scsi/README.FlashPoint [new file with mode: 0644]
drivers/scsi/aha1542.c
drivers/scsi/aha1542.h
drivers/scsi/g_NCR5380.c
drivers/scsi/hosts.c
drivers/scsi/hosts.h
drivers/scsi/scsi.c
drivers/scsi/scsi.h
drivers/scsi/sd.c
drivers/sound/soundcard.c
fs/binfmt_elf.c
fs/buffer.c
fs/isofs/rock.c
fs/locks.c
fs/namei.c
fs/nfs/inode.c
fs/proc/array.c
fs/proc/root.c
fs/super.c
include/linux/config.h
include/linux/fs.h
include/linux/if_frad.h
include/linux/mc146818rtc.h
include/linux/proc_fs.h
include/linux/sdla.h
mm/filemap.c
mm/memory.c
net/ipv4/tcp_input.c
scripts/Makefile
scripts/tkgen.c

diff --git a/CREDITS b/CREDITS
index 0ea5c7f1ec6da1a96c28e2e9194d29b242ed4961..48133c59b2045d41aa173c255bc61f8a4915372c 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -187,6 +187,14 @@ S: 3674 Oakwood Terrace #201
 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: Derbyshire DE4 3RL
 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: 59 Bugden Avenue
 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: POB 64132
 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: 1 Amherst Street
 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
@@ -1306,21 +1342,3 @@ 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
index 60d65268952afa7d1b074fdabff55c7cc095e80a..fbbdc92a1e0c5e8bd82df984cde23ee62f1013ce 100644 (file)
@@ -3,23 +3,27 @@ important packages for Linux.
 
 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 @@ SysVinit
 ========
 
    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 Linux C Library
    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 @@ The Termcap Library
 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 @@ ftp://sunsite.unc.edu/pub/Linux/GCC/termcap-2.0.7.tar.gz
 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 @@ At the time of writing:
 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
+
index 53e84aa3244db978ddc3d191e2219eb38de614a7..9fe4df72ad0cb6098cb0102a5c399faa55b8bbd8 100644 (file)
@@ -1225,27 +1225,29 @@ DTC3180/3280 SCSI support
 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 @@ CONFIG_SOFT_WATCHDOG
   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 @@ CONFIG_ISDN_DRV_TELES
 # 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 --git a/Documentation/rtc.txt b/Documentation/rtc.txt
new file mode 100644 (file)
index 0000000..9eeb425
--- /dev/null
@@ -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 */
index d53328452ff0e18a869fda417c375f668876484b..4b520cbb13c4fd3c90a91ebd95eb3de15de6271f 100644 (file)
@@ -241,3 +241,5 @@ this must be done manually -- no autodetection mechanisms are available.
                  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.
index b5023b3d51a570f08ef3e8f10b6e7826c76b9940..cef4fa73254f29cafbcdfa9d393fbf6065704b98 100644 (file)
@@ -99,7 +99,19 @@ S:   Maintained
 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)
index ba4b6b207f89cabf819aa5af189875d8937c7a2f..9476529388770f914f8bd63428369e3a91788489 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 88
+SUBLEVEL = 89
 
 ARCH = i386
 
@@ -328,9 +328,9 @@ mrproper: clean
        
 
 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
index 8bc9c304cec633aaa4b2a4642c4e374c7aa32c83..c2319cad99de9724b0d72022fc28eabb18b7d363 100644 (file)
@@ -195,6 +195,7 @@ CONFIG_PSMOUSE=y
 # CONFIG_FTAPE is not set
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
 
 #
 # Sound
index ad8a1f10bab494b38e23974c1c57234b4083a25f..5031a51d41071d6e6eead4839a53ab2102d8c610 100644 (file)
@@ -62,7 +62,7 @@ void show_mem(void)
        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 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
                        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 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
         */
        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 @@ void si_meminfo(struct sysinfo *val)
        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)
index 9aff2c47aa08f61710338e5667479c71749740e8..289f8cebc151c5815dc3004d55e4b2f19d837bcb 100644 (file)
@@ -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
@@ -738,6 +738,19 @@ res1:      ret
 
 #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:
@@ -947,7 +960,12 @@ scm1:      mov     ah,#0           ! Test the mode
        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_s3:   movb    al,#0x35        ! restore CRT register 0x35
 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
index 6f96917bf0ceb11e7081afc765d8633c24f51005..67838732220e2c1e39d9d52cc3befe8b21efdc36 100644 (file)
@@ -156,6 +156,7 @@ CONFIG_SERIAL=y
 # CONFIG_FTAPE is not set
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
 
 #
 # Sound
index 66cdf326db2411d50f27cbafad434d12c0ef336d..03d2c77e581e72bf6e94e829cd135ddda994e582 100644 (file)
@@ -199,7 +199,6 @@ void setup_arch(char **cmdline_p,
        /* 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");
index 63c52d675bb031cbf1c3ec8e2d3f37711544b0b3..e97ffce7b33051cbec279f8e6176a58fd6380fbc 100644 (file)
@@ -1808,7 +1808,7 @@ static void ide_release(struct inode * inode, struct file * file)
        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 @@ static void ide_release(struct inode * inode, struct file * file)
                        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);
index 945f0ef5dfb5f560f14e5c141483d507aabbcacc..ad345ba8f8c602174add50b7bcc2ed04bf5f6d30 100644 (file)
@@ -346,7 +346,9 @@ static void make_request(int major,int rw, struct buffer_head * bh)
        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:
index da26420764da2b37c0b0d077ae9a0e7e23d37858..0bf401cb84f1a01474c19c938fb4339569877756 100644 (file)
@@ -59,4 +59,5 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then
      bool '   Software Watchdog' CONFIG_SOFT_WATCHDOG
   fi
 fi
+bool 'Enhanced Real Time Clock Support' CONFIG_RTC
 endmenu
index ff0cf0b8f7c638d74a61080892f33b0b918054e0..9e95b4bea9c9edb0da04e7f449a53e02467337c2 100644 (file)
@@ -125,6 +125,11 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_RTC),y)
+M = y
+L_OBJS += rtc.o
+endif
+
 ifdef CONFIG_QIC02_TAPE
 L_OBJS += tpqic02.o 
 endif
index 5371f596d41282a9b1e70ab22950dd0a243e0911..30df1b2396c0bcadb8c1100fca7ed9415408e76d 100644 (file)
@@ -390,7 +390,7 @@ int chr_dev_init(void)
 #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
index 89be8a89a8f29afb07a92f2598fd508da7d71172..108b5fcf8bc5a4e115deaf741be21c20596dcc3f 100644 (file)
@@ -66,6 +66,7 @@ extern int psaux_init(void);
 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)
@@ -210,6 +211,9 @@ int misc_init(void)
 #ifdef CONFIG_APM
        apm_bios_init();
 #endif
+#ifdef CONFIG_RTC
+       rtc_init();
+#endif
 #endif /* !MODULE */
        if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
          printk("unable to get major %d for misc devices\n",
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
new file mode 100644 (file)
index 0000000..b082c23
--- /dev/null
@@ -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;
+}
+
index 3dfe2f3ac1d5c4e5c9baaabf0bbef76011178a7d..954bb2d3582d1d892fa7f74e9ad31ffefc0964b5 100644 (file)
@@ -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 @@ static int dlci_transmit(struct sk_buff *skb, struct device *dev)
       {
          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 @@ int dlci_config(struct device *dev, struct dlci_conf *conf, int get)
 
    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 @@ int dlci_config(struct device *dev, struct dlci_conf *conf, int get)
       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);
 }
index eead04fd7b093d7304fab2e6238dc12a261d6984..c7f6036443afbbb3f237891f61713ce916135997 100644 (file)
@@ -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 @@ static void sdla_read(struct device *dev, int addr, void *buf, short len)
    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 @@ static void sdla_write(struct device *dev, int addr, void *buf, short len)
    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 @@ static void sdla_clear(struct device *dev)
 {
    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 @@ static char sdla_byte(struct device *dev, int addr)
    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 @@ int sdla_z80_poll(struct device *dev, int z80_addr, int jiffs, char resp1, char
    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 @@ static void sdla_errors(struct device *dev, int cmd, int dlci, int ret, int len,
          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 @@ static int sdla_cmd(struct device *dev, int cmd, short dlci, short flags,
    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 @@ static int sdla_cmd(struct device *dev, int cmd, short dlci, short flags,
    len = 0;
    while (waiting && (jiffies <= jiffs))
    {
-      if (waiting++ % 4
+      if (waiting++ % 3
       {
          save_flags(pflags);
          cli();
@@ -462,13 +457,18 @@ static int sdla_cmd(struct device *dev, int cmd, short dlci, short flags,
       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 @@ int sdla_deactivate(struct device *slave, struct device *master)
       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 @@ int sdla_dlci_conf(struct device *slave, struct device *master, int get)
    struct frad_local *flp;
    struct frad_local *dlp;
    int               i;
+   short             len, ret;
 
    flp = slave->priv;
 
@@ -609,11 +613,18 @@ int sdla_dlci_conf(struct device *slave, struct device *master, int get)
       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 @@ int sdla_dlci_conf(struct device *slave, struct device *master, int get)
  *
  **************************/
 
+/* 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 @@ static int sdla_transmit(struct sk_buff *skb, struct device *dev)
       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 @@ static int sdla_transmit(struct sk_buff *skb, struct device *dev)
                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 @@ static int sdla_transmit(struct sk_buff *skb, struct device *dev)
       {
          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 @@ static void sdla_receive(struct device *dev)
    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 @@ static void sdla_receive(struct device *dev)
    {
       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;
+   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));
+   }
 
-         /* lets get the data */
-         sdla_read(dev, addr, skb_put(skb, len), len);
-         if (split)
+   /* 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_WINDOW(dev, SDLA_508_RXBUF_INFO);
-         pbuf->opp_flag = 0;
-         success = 1;
+            sdla_read(dev, addr, skb_put(skb, len2), len2);
+            if (split)
+               sdla_read(dev, buf_base, skb_put(skb, split), split);
+         }
 
          /* 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 @@ static void sdla_isr(int irq, void *dev_id, struct pt_regs * regs)
 
    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 @@ static void sdla_isr(int irq, void *dev_id, struct pt_regs * regs)
       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 @@ static int sdla_close(struct device *dev)
    }
 
    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 @@ static int sdla_open(struct device *dev)
    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 @@ static int sdla_config(struct device *dev, struct frad_conf *conf, int get)
       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 @@ static int sdla_config(struct device *dev, struct frad_conf *conf, int get)
                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 @@ static int sdla_config(struct device *dev, struct frad_conf *conf, int get)
       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 @@ static int sdla_config(struct device *dev, struct frad_conf *conf, int get)
             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 @@ static int sdla_reconfig(struct device *dev)
 
    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 @@ static int sdla_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
 
 /* ==========================================================
 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 @@ int sdla_init(struct device *dev)
 
    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++) 
index 72a6cb41cf8921732ff06f5e2a0e06ca68f2214f..8fb1365979a03b9c3d45fc82b89adf1f55773b4a 100644 (file)
@@ -21,7 +21,7 @@ static char *version =
 
 /* 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 @@ static void
 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);
index 82a050eab3ddb9dc58bcad2a08248214b63cbc2e..ec113fb3ff48533bcc0b4ef4493018626618595d 100644 (file)
@@ -125,10 +125,10 @@ struct wic_local {
        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
index af3cc1784c23c0a353bd90408ad082f8c100040f..beb4cc2b8c4334005065e034dda26b7c815c5c6c 100644 (file)
   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 @@ static BusLogic_HostAdapter_T
 
 
 /*
-  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 @@ static short
 
 /*
   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.
 */
 
@@ -166,56 +166,6 @@ const char *BusLogic_DriverInfo(SCSI_Host_T *Host)
 }
 
 
-/*
-  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.
@@ -256,6 +206,52 @@ static void BusLogic_UnregisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
 }
 
 
+/*
+  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 void BusLogic_UnregisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
 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 @@ static void BusLogic_DestroyCCBs(BusLogic_HostAdapter_T *HostAdapter)
 
 /*
   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 @@ static void BusLogic_DeallocateCCB(BusLogic_CCB_T *CCB)
   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 @@ static int BusLogic_Command(BusLogic_HostAdapter_T *HostAdapter,
     {
     case BusLogic_InquireInstalledDevicesID0to7:
     case BusLogic_InquireInstalledDevicesID8to15:
+    case BusLogic_InquireDevices:
       /* Approximately 60 seconds. */
       TimeoutCounter = loops_per_sec << 2;
       break;
@@ -486,6 +495,8 @@ static int BusLogic_Command(BusLogic_HostAdapter_T *HostAdapter,
        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;
@@ -550,6 +561,121 @@ static int BusLogic_Command(BusLogic_HostAdapter_T *HostAdapter,
 }
 
 
+/*
+  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 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
   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 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
     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:
@@ -834,6 +965,54 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
                  BT-542B/742A (revision G and below)
     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.
   */
@@ -902,31 +1081,28 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
     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 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
     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 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
       | 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 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
     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 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
   */
   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 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
   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 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
   */
   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 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
   /*
     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 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
     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 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
   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 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
   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 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
 
 
 /*
-  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",
@@ -1206,17 +1461,6 @@ static boolean BusLogic_AcquireResources(BusLogic_HostAdapter_T *HostAdapter,
       enable_dma(HostAdapter->DMA_Channel);
       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,
   */
@@ -1306,51 +1550,51 @@ static boolean BusLogic_InitializeHostAdapter(BusLogic_HostAdapter_T
   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 @@ static boolean BusLogic_InitializeHostAdapter(BusLogic_HostAdapter_T
     }
   /*
     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_InitializeHostAdapter(BusLogic_HostAdapter_T
 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 @@ static boolean BusLogic_InquireTargetDevices(BusLogic_HostAdapter_T
       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.
+    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 (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");
+  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 @@ static boolean BusLogic_InquireTargetDevices(BusLogic_HostAdapter_T
        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 @@ static boolean BusLogic_InquireTargetDevices(BusLogic_HostAdapter_T
     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)
@@ -1538,6 +1790,75 @@ static boolean BusLogic_InquireTargetDevices(BusLogic_HostAdapter_T
 }
 
 
+/*
+  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
@@ -1619,6 +1940,7 @@ int BusLogic_DetectHostAdapter(SCSI_Host_Template_T *HostTemplate)
             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 @@ int BusLogic_DetectHostAdapter(SCSI_Host_Template_T *HostTemplate)
       /*
        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 @@ int BusLogic_DetectHostAdapter(SCSI_Host_Template_T *HostTemplate)
          /*
            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 @@ int BusLogic_ReleaseHostAdapter(SCSI_Host_T *Host)
   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 @@ static void BusLogic_InterruptHandler(int IRQ_Channel,
 {
   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 @@ static void BusLogic_InterruptHandler(int IRQ_Channel,
       /*
        Acquire exclusive access to Host Adapter.
       */
-      BusLogic_LockHostAdapterID(HostAdapter);
+      BusLogic_AcquireHostAdapterLockID(HostAdapter, &Lock);
       /*
        Read the Host Adapter Interrupt Register.
       */
@@ -1799,14 +2128,14 @@ static void BusLogic_InterruptHandler(int IRQ_Channel,
          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 @@ static void BusLogic_InterruptHandler(int IRQ_Channel,
                {
                  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 @@ static void BusLogic_InterruptHandler(int IRQ_Channel,
                            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,25 +2211,8 @@ static void BusLogic_InterruptHandler(int IRQ_Channel,
       /*
        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 @@ static void BusLogic_InterruptHandler(int IRQ_Channel,
       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.
       */
-      if (CCB->Opcode == BusLogic_SCSIBusDeviceReset)
+      BusLogic_AcquireHostAdapterLockID(HostAdapter, &Lock);
+      /*
+       Process the Completed CCB.
+      */
+      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 @@ static boolean BusLogic_WriteOutgoingMailbox(BusLogic_HostAdapter_T
                                             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 @@ static boolean BusLogic_WriteOutgoingMailbox(BusLogic_HostAdapter_T
       */
       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 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
   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 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
       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 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
     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 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
   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 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
        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.
+       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->QueuedOperationCount[TargetID] == 0)
-       HostAdapter->LastSequencePoint[TargetID] = CurrentTime;
-      else if (CurrentTime - HostAdapter->LastSequencePoint[TargetID] > 2*HZ)
+      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 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
   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 @@ int BusLogic_AbortCommand(SCSI_Command_T *Command)
 {
   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.
+    Acquire exclusive access to Host Adapter.
   */
-  InterruptRegister = BusLogic_ReadInterruptRegister(HostAdapter);
-  if (InterruptRegister & BusLogic_InterruptValid)
+  BusLogic_AcquireHostAdapterLock(HostAdapter, &Lock);
+  /*
+    If this Command has already completed, then no Abort is necessary.
+  */
+  if (Command->serial_number != Command->serial_number_at_timeout)
     {
-      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;
+      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;
     }
   /*
-    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)
+    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')
     {
-      /*
-       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 - "
+            "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;
+    }
+  else
+    {
+      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 @@ static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *HostAdapter,
   /*
     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;
   /*
-    Perform completion processing for the Command being 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);
+  /*
+    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.
+    For Synchronous Resets, arrange for the interrupt handler to perform
+    completion processing for the Command being Reset.
   */
-  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);
+  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 @@ static int BusLogic_BusDeviceReset(BusLogic_HostAdapter_T *HostAdapter,
       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 @@ static int BusLogic_BusDeviceReset(BusLogic_HostAdapter_T *HostAdapter,
   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 @@ int BusLogic_ResetCommand(SCSI_Command_T *Command)
 
 /*
   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 @@ int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, KernelDevice_T Device,
   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 @@ int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, KernelDevice_T Device,
     }
   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 @@ int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, KernelDevice_T Device,
 /*
   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 @@ int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, KernelDevice_T Device,
   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 @@ int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, KernelDevice_T Device,
 
   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 @@ int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, KernelDevice_T Device,
                        "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 @@ int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, KernelDevice_T Device,
                        "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 @@ void BusLogic_Setup(char *Strings, int *Integers)
   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 @@ void BusLogic_Setup(char *Strings, int *Integers)
                       "(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 @@ void BusLogic_Setup(char *Strings, int *Integers)
     }
   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 @@ void BusLogic_Setup(char *Strings, int *Integers)
          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 @@ void BusLogic_Setup(char *Strings, int *Integers)
              break;
            default:
              Strings--;
-             TargetID = BusLogic_MaxTargetIDs;
+             TargetID = BusLogic_MaxTargetDevices;
              break;
            }
     }
@@ -2717,47 +3320,47 @@ void BusLogic_Setup(char *Strings, int *Integers)
       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;
            }
     }
@@ -2770,7 +3373,6 @@ void BusLogic_Setup(char *Strings, int *Integers)
   Include Module support if requested.
 */
 
-
 #ifdef MODULE
 
 SCSI_Host_Template_T driver_template = BUSLOGIC;
index c9410e71c001aa17eac2321ca007ff5bf213d605..f3d26c4684f92e883ce0e0e7b8d540319ec6875a 100644 (file)
@@ -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_ReleaseHostAdapter(SCSI_Host_T *);
 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 @@ int BusLogic_BIOSDiskParameters(SCSI_Disk_T *, KernelDevice_T, int *);
 
 
 /*
-  Define the maximum number of Target IDs 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 the maximum number of Target Devices supported by this driver.
 */
 
-#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 @@ int BusLogic_BIOSDiskParameters(SCSI_Disk_T *, KernelDevice_T, int *);
 #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 @@ typedef enum
 {
   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 @@ typedef enum
   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 @@ BusLogic_OperationCode_T;
 
 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 unsigned char BusLogic_InstalledDevices_T[BusLogic_MaxTargetIDs];
 
 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 @@ BusLogic_Configuration_T;
 
 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 @@ typedef BusLogic_SynchronousValue_T
   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 @@ BusLogic_SetupInformation_T;
 
 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;
 
@@ -400,6 +411,26 @@ typedef unsigned char BusLogic_FirmwareVersion3rdDigit_T;
 typedef unsigned char BusLogic_FirmwareVersionLetter_T;
 
 
+/*
+  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 @@ typedef unsigned char BusLogic_BoardModelNumber_T[5];
 
 
 /*
-  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 @@ typedef struct BusLogic_ExtendedSetupInformation
   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;
 
@@ -448,6 +481,47 @@ BusLogic_ExtendedSetupInformation_T;
 typedef unsigned char BusLogic_RoundRobinModeRequest_T;
 
 
+/*
+  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
@@ -469,7 +543,7 @@ typedef unsigned char BusLogic_ModifyIOAddressRequest_T;
 
 /*
   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 @@ typedef unsigned char BusLogic_RequestedReplyLength_T;
 
 /*
   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 @@ typedef enum
   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 unsigned char SCSI_SenseData_T[BusLogic_SenseDataMaxLength];
 
 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 @@ BusLogic_CCB_T;
 
 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 @@ BusLogic_OutgoingMailbox_T;
 
 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 @@ static char
 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 @@ typedef struct BusLogic_HostAdapter
   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 @@ typedef struct BusLogic_HostAdapter
   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 @@ BIOS_DiskParameters_T;
 
 
 /*
-  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 @@ unsigned char BusLogic_ReadGeometryRegister(BusLogic_HostAdapter_T *HostAdapter)
 
 
 /*
-  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 inline void BusLogic_Delay(int Seconds)
 
 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 */
index 1f4e9c532fbb829fc18e66b55ae998f74ed0a55c..7b154dbb097b085f3d75faf0cd812917aec9fa8e 100644 (file)
@@ -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.
index 841ce9205b38722da6cd549d4ecdc6e8d477b2e0..1e0aa6bf04927a9009aa13d9985ed1451a4d7a9b 100644 (file)
@@ -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 @@ of bus architectures by virtue of their MultiMaster ASIC technology.  This
 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 @@ performance and error recovery to their particular needs.
 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 @@ driver and SCSI subsystem at startup, along with any subsequent system messages
 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 @@ o Performance Features
   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 @@ o PCI Configuration Support
   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 @@ the date of this document.  It is recommended that anyone purchasing a BusLogic
 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-540CF    ISA         Fast Single-ended SCSI-2
 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-742A       EISA    Single-ended SCSI-2 (742A revisions A - G)
 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 @@ file "BusLogic.c".  The following examples may be useful as a starting point:
 
   "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 @@ appropriate, and reboot.
 
 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 --git a/drivers/scsi/README.FlashPoint b/drivers/scsi/README.FlashPoint
new file mode 100644 (file)
index 0000000..c3472d6
--- /dev/null
@@ -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
index b415545f57e6b2e37b1eeb86df2e0e4e3ad58c3d..9e580b287edea9bcd2483789373a57de012f0a7e 100644 (file)
@@ -1179,7 +1179,7 @@ int aha1542_abort(Scsi_Cmnd * SCpnt)
    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 @@ int aha1542_reset(Scsi_Cmnd * SCpnt)
     /*
      * 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.
index 9dbc8863054fa3bb740b1e13ea0aa768d1dfa6ca..6c250d5a54d60bbb19ed15a90382e9a854f5e9e8 100644 (file)
@@ -134,7 +134,7 @@ int aha1542_detect(Scsi_Host_Template *);
 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
index 414fc70ff7f9f807bbe760822deb7d47167d25ba..4cf3210679d263cbd97363092b9ea6e1ec8d855d 100644 (file)
@@ -122,13 +122,15 @@ static void internal_setup(int board, char *str, int *ints) {
     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) {
index 69a404415f6712e2b0297f2be3d9ea7f61079193..d0f6d684f4524820014776a8d3864f5aab4fac6c 100644 (file)
@@ -333,6 +333,9 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
     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
index 7ca8200a33430c46c78d1a91a84558ace6cf5ddc..471f32d2cee2713216869249b1c4dbcd1d6efa73 100644 (file)
@@ -156,7 +156,7 @@ typedef struct      SHT
      * 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 @@ struct Scsi_Host
     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 @@ struct Scsi_Host
      * 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 */
 };
 
index 7e2f4e48174341ac5219f5e3734d1b258adea178..4763ed3fd1f6b8615b1316e1aea9a6b0ad4654d7 100644 (file)
@@ -84,7 +84,7 @@ const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, 12, 12, 10, 10 };
 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 @@ Scsi_Device * scsi_devices = NULL;
 /* 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 @@ extern int dispatch_scsi_info(int ino, char *buffer, char **start,
 
 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 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded,
   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 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
 #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 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
  * 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 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid)
 #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 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid)
         * 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 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
     
     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 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
      * 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 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
     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 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
        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 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
                    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 @@ inline void internal_cmnd (Scsi_Cmnd * SCpnt)
      * 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 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
     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 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
     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 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
            /* 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 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
                       " 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 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
                    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 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
            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 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
            {
                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 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
  */
 
 
-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 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why, int pid)
         * 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 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why, int pid)
                   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 @@ void scsi_mark_host_bus_reset(struct Scsi_Host *Host)
 }
 
 
-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 @@ int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
     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 @@ int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
      * 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 @@ int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
         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 @@ int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
        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 @@ int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
 #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 @@ int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
                }
                
                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 @@ int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
                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 @@ int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
                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 @@ static void scsi_main_timeout(void)
      * 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 @@ static int update_timeout(Scsi_Cmnd * SCset, int timeout)
     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 @@ static int update_timeout(Scsi_Cmnd * SCset, int timeout)
        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_init_free(char * ptr, unsigned int size)
 
 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 @@ void scsi_build_commandblocks(Scsi_Device * SDpnt)
        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 @@ int scsi_dev_init(void)
 
     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 @@ static void print_inquiry(unsigned char *data)
 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 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
        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 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
      * 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("add-single-device", buffer + 5, 17)) {
+       p = buffer + 23;
 
-    if(!strncmp("singledevice", buffer + 5, 12)) {
-       p = buffer + 17;
+        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);
 
-       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]);
+       printk("scsi singledevice %d %d %d %d\n", host, channel,
+                       id, lun);
 
-       while(scd && (scd->host->host_no != parameter[0] 
-             || scd->channel != parameter[1] 
-             || scd->id != parameter[2] 
-             || scd->lun != parameter[3])) {
+       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 @@ static void resize_dma_pool(void)
     
     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++;
        }
     }
index a4e569424048d552b61ffa7a14c30b796f08fa3a..6a1c7627a6932ec7c72b94ba02914af9f9330e30 100644 (file)
@@ -163,6 +163,7 @@ typedef struct scsi_device {
     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 @@ typedef struct scsi_device {
     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 @@ typedef struct scsi_device {
     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 @@ struct scatterlist {
  * 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 @@ typedef struct scsi_cmnd {
     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 @@ typedef struct scsi_cmnd {
 
     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 @@ typedef struct scsi_cmnd {
  *  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 void scsi_do_cmd (Scsi_Cmnd *, const void *cmnd ,
 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;
 
index c9196f5a742a5fe0afc50251361fac45ec7611b1..271b27ddb837674410d281d09803b6f996da460a 100644 (file)
@@ -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)
index 222f709e21105c6e7058789e087fdd68ffb6b6c2..5c2a81b4b526825d0a2d819e777b274006f4b878 100644 (file)
@@ -170,13 +170,13 @@ sound_ioctl (inode_handle * inode, file_handle * file,
 
       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;
index b41138ead50c25e555a346710be866dd223f40f6..1259fe2ec47e1ff4bee71b8b37fefe03858ad6f8 100644 (file)
@@ -964,16 +964,17 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
        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 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
                struct elf_phdr phdr;
                size_t sz;
 
-               if (!maydump(vma))
-                       continue;
                i++;
 
                sz = vma->vm_end - vma->vm_start;
@@ -1162,9 +1161,9 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
                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;
index 73f1507071495aed5aa468f7b5da5755c65773df..7623b608af1bc2a91196161f9743cc409700e9e6 100644 (file)
@@ -1818,9 +1818,11 @@ struct wait_queue * bdflush_done = NULL;
 
 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);
+       }
 }
 
 
index 2138c032c53c19358d86294237bbf8cdb43bc1fe..b96e113cd205341d37a3c7a10c7b6ca7408f30c9 100644 (file)
@@ -507,6 +507,7 @@ char * get_rock_ridge_symlink(struct inode * inode)
         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;
index 1f2f5ed7e92ec1f778b391df49a1f6e4077a5b1d..57e53dc6d2f9e0b344bbba3872f42060bd90b93d 100644 (file)
@@ -861,26 +861,29 @@ static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
 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);
index 3865b8c9ee4af58543e87e423023286b0fbc9890..a7895138b03c2a9f9bff16b596dc65fcbef378b7 100644 (file)
@@ -388,7 +388,8 @@ int open_namei(const char * pathname, int flag, int mode,
        /* 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 @@ int open_namei(const char * pathname, int flag, int mode,
                 * 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;
                }
index c7cce15b7b85183bb213071f026210e814b3d3b7..dd1e6dd2122d004319435e061335f61cbd076eee 100644 (file)
@@ -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>
index 280ca2164957b5ab03b7a139a76ec137ec70a3b2..c7cd52ed2def4c044ea2d2271aee8d75422fcfcc 100644 (file)
@@ -959,6 +959,7 @@ extern int get_dma_list(char *);
 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 @@ static int get_root_array(char * page, int type, char **start, off_t offset, int
 
                 case PROC_MTAB:
                        return get_filesystem_info( page );
+#ifdef CONFIG_RTC
+               case PROC_RTC:
+                       return get_rtc_status(page);
+#endif
        }
        return -EBADF;
 }
index 0d85692fcce4b35224fb2a1ec6bcdd8b4b315b2c..267222e31bad59716f940d22a88a2bf474ef839e 100644 (file)
@@ -352,6 +352,12 @@ void proc_root_init(void)
                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, } );
index 798ecbe64d477dd2cb51ac03d6716d7c9f094360..7f189b2c1e1dfc6f3e0742f9dca883c293b83fce 100644 (file)
@@ -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 @@ asmlinkage int sys_sysfs(int option, ...)
        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;
        }
index a54cdff20da76db831982e307a7337ea34ce49da..add2f6bb53bf25b3f1c749d8bbbb17366ec1766f 100644 (file)
@@ -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
index fe8257c672b46f425f1e158a4621a9810413aafb..5420df4b25c083688ac69cadfb5d4cb08c0fa748 100644 (file)
@@ -320,7 +320,7 @@ struct file {
        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;
index 928e8d93113cbbe0d6018240d8215749fd0a29f4..52afe58c88643cafff4e3630692da7070ab3547c 100644 (file)
  *
  * 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
index d2e709a1adae4bb47b2a992e8fb23b2139ec5af7..55b535f3f8469755644d8ca81deea31214808b1d 100644 (file)
@@ -106,4 +106,22 @@ outb_p((val),RTC_PORT(1)); \
 #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 */
index 91882ed35d0ec44d9f233a8e6c1f1143c7ebfa19..46c3a2e6a37f7c08e998986e2627f83ebecc7090 100644 (file)
@@ -41,7 +41,8 @@ enum root_directory_inos {
        PROC_CMDLINE,
        PROC_SYS,
        PROC_MTAB,
-       PROC_MD
+       PROC_MD,
+       PROC_RTC
 };
 
 enum pid_directory_inos {
index baae87c854e734744d8f4c379f7c513ca93b42d8..44ae55b1c4275af00080130b2aaaeb090fa626b6 100644 (file)
@@ -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 @@ void sdla(void *cfg_info, char *dev, struct frad_conf *conf, int quiet);
 
 /* 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
index 5f9a3bbd3c52b9b9521ff81479a721294b5c42a6..02731ad262479e16009519080bdb99239ff7853a 100644 (file)
 #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 @@ static inline unsigned long generic_file_readahead(struct file * filp, struct in
        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 @@ static inline unsigned long generic_file_readahead(struct file * filp, struct in
        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;
-
-                       if (rapos < inode->i_size) {
-                               a_page = find_page(inode, rapos);
-                               if (a_page) {
-                                       if (PageLocked(a_page))
-                                               max_ahead = 0;
-                                       a_page->count--;
-                               }
+               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--;
                        }
-                       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,26 +388,21 @@ static inline unsigned long generic_file_readahead(struct file * filp, struct in
        }
 /*
  * 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
  */
@@ -424,77 +416,86 @@ static inline unsigned long generic_file_readahead(struct file * filp, struct in
 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.
- */
-       else {
-               try_async = 0;
-               filp->f_rapos = 0;
-               filp->f_ralen = 0;
-               filp->f_ramax = 0;
-       }
-
 /*
  * Compute a good value for read-ahead max
- * Try first some value near count.
- * Do at least MIN_READAHEAD and at most MAX_READAHEAD.
+ * 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)
  */
-       if (filp->f_ramax < count)
-               filp->f_ramax = count & PAGE_MASK;
+       if (pos + count <= (PAGE_SIZE >> 1)) {
+               try_async = 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;
+               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;
@@ -537,8 +538,19 @@ found_page:
                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;
index b82abbe17e8aca1d7a6c16a622c53f707bc38d14..9b0883d69c8e210bd6c6b7d0917622ad5d286fd4 100644 (file)
@@ -742,7 +742,7 @@ check_wp_fault_by_hand:
 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:
index f8c31c6f7e8dc55a115c37b03432c0458eb40d2e..d33075d3390096a7436061f4ec18f4c0dc7ab967 100644 (file)
@@ -705,10 +705,11 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
         *      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 @@ static void tcp_queue(struct sk_buff * skb, struct sock * sk, struct tcphdr *th)
                    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);
            }
        }
 }
index bc8c6f9a86f2ea507a17237a201eade18f6e9815..f25be0d321aa65f4f8155fa751d8ad1687e7a8cd 100644 (file)
@@ -35,6 +35,6 @@ tkgen.o: tkgen.c tkparse.h
        $(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
index 13da17adda2f9ddf5d2c416d29c3c79f11e0ec55..eb549023d86c562c144e675e6c24752dc538550a 100644 (file)
  *                  (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 @@ static void start_proc(char * label, int menu_num, int flag)
   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 @@ static void end_proc(int menu_num)
   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");
 
   /*