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

diff -urN linux-2.0.37-pre3/arch/i386/config.in linux-2.0.37-pre4/arch/i386/config.in
--- linux-2.0.37-pre3/arch/i386/config.in	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/arch/i386/config.in	2003-08-15 15:04:28.000000000 -0700
@@ -22,7 +22,20 @@
 comment 'General setup'
 
 bool 'Kernel math emulation' CONFIG_MATH_EMULATION
-int ' Max physical memory in MB' CONFIG_MAX_MEMSIZE 1024
+choice 'Nemory configuration' \
+	"Standard	CONFIG_MEM_STD	\
+	 Enterprise	CONFIG_MEM_ENT	\
+	 Custom		CONFIG_MEM_SPECIAL" Standard
+
+if [ "CONFIG_MEM_SPECIAL" = "y" ]; then
+	int ' Max physical memory in MB' CONFIG_MAX_MEMSIZE 1024
+fi
+if [ "$CONFIG_MEM_ENT" = "y" ]; then
+	define_int CONFIG_MAX_MEMSIZE 2048
+fi
+if [ "$CONFIG_MEM_STD" = "y" ]; then
+	define_int CONFIG_MAX_MEMSIZE 1024
+fi
 bool 'Networking support' CONFIG_NET
 bool 'Limit memory to low 16MB' CONFIG_MAX_16M
 bool 'PCI bios support' CONFIG_PCI
diff -urN linux-2.0.37-pre3/Documentation/Configure.help linux-2.0.37-pre4/Documentation/Configure.help
--- linux-2.0.37-pre3/Documentation/Configure.help	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/Documentation/Configure.help	2003-08-15 15:04:28.000000000 -0700
@@ -491,6 +491,16 @@
   be called fit3.o.  You must also have a high-level driver for the
   type of device that you want to support.
 
+Freecom IQ ASIC-2 protocol
+CONFIG_PARIDE_FRIQ
+  This option enables support for version 2 of the Freecom IQ parallel
+  port IDE adapter.  This adapter is used by the Maxell Superdisk 
+  drive.  If you chose to build PARIDE support into your kernel, you
+  may answer Y here to build in the protocol driver, otherwise you
+  should answer M to build it as a loadable module. The module will be
+  called friq.o. You must also have a high-level driver for the type
+  of device that you want to support. 
+
 FreeCom power protocol
 CONFIG_PARIDE_FRPW
   This option enables support for the Freecom power parallel port IDE
@@ -836,15 +846,33 @@
   certain BIOSes if your computer uses a PCI bus system. This is
   recommended; say Y.
 
-Intel 82371 PIIX (Triton I/II) DMA support
+Generic IDE (U)DMA support
 CONFIG_BLK_DEV_TRITON
-  If your PCI system uses an IDE hard drive (as opposed to SCSI, say)
-  and includes the Intel Triton I/II IDE interface chipset (i82371FB,
+  If your PCI system uses an EIDE hard disk (as opposed to SCSI, say)
+  and includes one of the Intel (U)DMA IDE Southbridge ICs (i82371FB,
   i82371SB or i82371AB), you will want to enable this option to allow
-  use of bus-mastering DMA data transfers. Read the comments at the
-  beginning of drivers/block/triton.c and Documentation/ide.txt.
+  use of bus-mastering DMA data transfers. This increases transfer
+  rates and reduces latencies and CPU utilization. Read the comments in
+  Documentation/ide.txt and Documentation/udma.txt.
   Check the file Documentation/Changes for location and latest version
-  of the hdparm utility. It is safe to say Y to this question.
+  of the hdparm utility. There are now several more chipsets added, to
+  include offboard PCI-IDE-UDMA cards and newer SiS and VIA chipsets.
+  It is safe to say Y to this question, as long as your PCI bus is
+  operating within specs (33MHz recommended).
+
+Boot off-board chipsets first support
+CONFIG_BLK_DEV_OFFBOARD
+  Normally, IDE controllers built into the motherboard (on-board
+  controllers) are assigned to ide0 and ide1 while those on add-in
+  PCI cards (off-board controllers) are relegated to ide2 and ide3.
+  Saying Y to here will reverse the situation, with off-board
+  controllers on ide0/1 and on-board controllers on ide2/3. This
+  can improve the usability of some boot managers such as LILO
+  when booting from a drive on an off-board controller.
+  Note that this will rearrange the order of the hd* devices and
+  may require modification of fstab and other files.
+  Check the file Documentation/udma.txt
+  If in doubt, say N.
 
 System V IPC
 CONFIG_SYSVIPC
@@ -4722,6 +4750,16 @@
   rules require. If you have a PPro or later SMP and one or more CPU's
   report a value of about 2-3 bogomips enable this.
 
+Nemory configuration
+CONFIG_MEM_STD
+  There are three memory configurations available. The standard
+  configuration allows use of just under 1GB of RAM with 3GB of
+  virtual space per process. The enterprise configuration allows
+  2Gigabytes of physical memory but limits the per process address
+  space to 2Gigabytes. The custom option allows you to specify the
+  split subject to kernel constraints. If you don't know how it works
+  don't pick it.
+
 # need an empty line after last entry, for sed script in Configure.
 
 #
diff -urN linux-2.0.37-pre3/Documentation/ide.txt linux-2.0.37-pre4/Documentation/ide.txt
--- linux-2.0.37-pre3/Documentation/ide.txt	1998-07-13 13:47:25.000000000 -0700
+++ linux-2.0.37-pre4/Documentation/ide.txt	2003-08-15 15:04:28.000000000 -0700
@@ -5,6 +5,9 @@
 	Gadi Oxman   <gadio@netvision.net.il>	-- tapes, disks, whatever
 	Scott Snyder <snyder@fnald0.fnal.gov>	-- cdroms, ATAPI, audio
 
+UDMA support was added for various chipsets, from kernel 2.0.35 on. Check
+the udma.txt file in this directory for details.
+
    +-----------------------------------------------------------------+
    |  The hdparm utility for controlling various IDE features is     |
    |  packaged separately.  Look for it on popular linux FTP sites.  |
@@ -483,3 +486,135 @@
 For really high end systems, go for fast/wide 7200rpm SCSI.  But it'll cost ya!
 
 mlord@pobox.com
+================================================================================
+
+DMA Bus Master transfer
+-----------------------
+The triton.c driver provides support for the DMA Bus Mastering functions of
+the Intel PCI Triton I/II chipsets (i82371FB or i82371SB).
+
+Pretty much the same code will work for the OPTi "Viper" chipset. Look for
+DMA support for this in linux kernel 2.1.xx, when it appears.
+
+DMA is currently supported only for hard disk drives (not cdroms).
+
+Support for cdroms will likely be added at a later date, after broader
+experience has been obtained with hard disks.
+
+Up to four drives may be enabled for DMA, and the motherboard chipset will
+(hopefully) arbitrate the PCI bus among them.  Note that the i82371 chip
+provides a single "line buffer" for the BM IDE function, so performance of
+multiple (two) drives doing DMA simultaneously will suffer somewhat, as they
+contest for that resource bottleneck.  This is handled transparently inside
+the i82371 chip.
+
+The SiS 5513 controller has two completely independent IDE controller units,
+each with a 64-byte line buffer (same size as the Intel); there is no
+bottleneck in simultaneous (U)DMA transfers for this resource. The 5513 is
+built-in the SiS 5571, 5598 and 5591 chipsets.
+
+The VIA chipsets like the Intel have a single 64 byte line buffer, but it
+can be split 1/2-1/2 or 1/4-3/4 between both channels.
+
+By default, DMA support is prepared for use, but is currently enabled only
+for drives which support multi-word DMA mode2 (mword2), or which are
+recognized as "good" (see table below).  Drives with only mode0 or mode1
+(single or multi) DMA should also work with this chipset/driver (eg.
+MC2112A) but are not enabled by default.  Use "hdparm -i" to view modes
+supported by a given drive.
+
+The hdparm-3.3 (patched) utility can be used to manually enable /disable DMA
+support, but must be (re-)compiled against this kernel version or later.
+
+Michel Aubry has produced a patch against hdparm-3.3 to support UDMA.
+
+To enable DMA, use "hdparm -d1 /dev/hd?" on a per-drive basis after booting.
+If problems arise, ide.c will disable DMA operation after a few retries.
+This error recovery mechanism works and has been extremely well exercised.
+
+IDE drives, depending on their vintage, may support several different modes
+of DMA operation.  The boot-time modes are indicated with a "*" in the
+"hdparm -I" listing, and can be changed with *knowledgeable* use of the
+"hdparm -X" feature (X32 for DMA 0, X33 for DMA 1, X34 for DMA 2, X64 for
+UDMA 0, X65 for UDMA 1 and X66 for UDMA 2).
+
+Testing was done with an ASUS P55TP4XE/100 system and the following drives:
+
+  Quantum Fireball 1080A (1Gig w/83kB buffer), DMA mode2, PIO mode4.
+ 	- DMA mode2 works well (7.4MB/sec), despite the tiny on-drive buffer.
+ 	- This drive also does PIO mode4, at about the same speed as DMA mode2.
+ 	  An awesome drive for the price!
+ 
+  Fujitsu M1606TA (1Gig w/256kB buffer), DMA mode2, PIO mode4.
+ 	- DMA mode2 gives horrible performance (1.6MB/sec), despite the good
+ 	  size of the on-drive buffer and a boasted 10ms average access time.
+ 	- PIO mode4 was better, but peaked at a mere 4.5MB/sec.
+ 
+  Micropolis MC2112A (1Gig w/508kB buffer), drive pre-dates EIDE and ATA2.
+ 	- DMA works fine (2.2MB/sec), probably due to the large on-drive buffer.
+ 	- This older drive can also be tweaked for fastPIO (3.7MB/sec) by using
+ 	  maximum clock settings (5,4) and setting all flags except prefetch.
+ 
+  Western Digital AC31000H (1Gig w/128kB buffer), DMA mode1, PIO mode3.
+ 	- DMA does not work reliably.  The drive appears to be somewhat tardy
+ 	  in deasserting DMARQ at the end of a sector.  This is evident in
+ 	  the observation that WRITEs work most of the time, depending on
+ 	  cache-buffer occupancy, but multi-sector reads seldom work.
+ 
+Testing was done with a Gigabyte GA-586 ATE system and the following drive:
+(Uwe Bonnes - bon@elektron.ikp.physik.th-darmstadt.de)
+ 
+  Western Digital AC31600H (1.6Gig w/128kB buffer), DMA mode2, PIO mode4.
+ 	- much better than its 1Gig cousin, this drive is reported to work
+ 	  very well with DMA (7.3MB/sec).
+ 
+Other drives:
+ 
+  Maxtor 7540AV (515Meg w/32kB buffer), DMA modes mword0/sword2, PIO mode3.
+ 	- a budget drive, with budget performance, around 3MB/sec.
+ 
+  Western Digital AC2850F (814Meg w/64kB buffer), DMA mode1, PIO mode3.
+ 	- another "caviar" drive, similar to the AC31000, except that this one
+ 	  worked with DMA in at least one system.  Throughput is about 3.8MB/sec
+ 	  for both DMA and PIO.
+ 
+  Conner CFS850A (812Meg w/64kB buffer), DMA mode2, PIO mode4.
+ 	- like most Conner models, this drive proves that even a fast interface
+ 	  cannot improve slow media.  Both DMA and PIO peak around 3.5MB/sec.
+ 
+  Maxtor 71260AT (1204Meg w/256kB buffer), DMA mword0/sword2, PIO mode3.
+ 	- works with DMA, on some systems (but not always on others, eg. Dell),
+ 	  giving 3-4MB/sec performance, about the same as mode3.
+ 
+  IBM DHEA 36480 (6197Meg w/476kB buffer), DMA mode2, PIO mode4, UDMA mode2
+	- works with DMA and UDMA on systems that support it. This drive and its
+	  larger 8.4GB cousin provide throughput of 9.8MB/sec under UDMA.
+ 
+If you have any drive models to add, email your results to:  mlord@pobox.com
+Keep an eye on /var/adm/messages for "DMA disabled" messages.
+ 
+Some people have reported trouble with Intel Zappa motherboards.
+This can be fixed by upgrading the AMI BIOS to version 1.00.04.BS0,
+available from ftp://ftp.intel.com/pub/bios/10004bs0.exe
+(thanks to Glen Morrell <glen@spin.Stanford.edu> for researching this).
+ 
+And, yes, Intel Zappa boards really *do* use the Triton IDE ports.
+ 
+Changes by Michel Aubry, Andre Hedrick and Andrew D. Balsa, June 1998:
+  a) Added support for non-Intel chipsets that support Bus Mastering DMA.
+  b) Added support for UDMA (33Mb/s) drives and controllers. Note that UDMA
+     support must be enabled in the BIOS, and that both the hard disk drive
+     _and_ the chipset must support UDMA.
+  On the IBM DHEA-36480 drive, transfer rates go from 7.76Mb/s to 9.76Mb/s,
+  a 25% improvement with zero cost (DMA mode2 to UDMA mode2).
+ 
+Extra UDMA PCI controller card support by Andre M. Hedrick, June 1998:
+  - PDC20246 Promise Ultra33 UDMA.
+  - AEC6210  Artop Electronics Corp. ACARD
+        sold under SIIG CN2449 UltraIDE Pro.
+  - HPT343   Triones Technologies (HighPoint Technologies) Inc.
+        future support -- nonbooting cards, need MNDA approval for
+        information release.
+        sold under Digital Research DRIDEUDMA.
+
+For more information on UDMA support, check /Documentation/udma.txt.
diff -urN linux-2.0.37-pre3/Documentation/paride.txt linux-2.0.37-pre4/Documentation/paride.txt
--- linux-2.0.37-pre3/Documentation/paride.txt	1998-11-15 10:32:44.000000000 -0800
+++ linux-2.0.37-pre4/Documentation/paride.txt	2003-08-15 15:04:28.000000000 -0700
@@ -64,6 +64,7 @@
 	SyQuest EZ-135, EZ-230 & SparQ drives
 	Avatar Shark
 	Imation Superdisk LS-120
+	Maxell Superdisk LS-120
 	FreeCom Power CD 
 	Hewlett-Packard 5GB and 8GB tape drives
 	Hewlett-Packard 7100 and 7200 CD-RW drives
@@ -98,6 +99,7 @@
         epia    Shuttle EPIA                           (UK)
 	fit2    FIT TD-2000			       (US)
 	fit3    FIT TD-3000			       (US)
+	friq    Freecom IQ cable                       (DE)
         frpw    Freecom Power                          (DE)
         kbic    KingByte KBIC-951A and KBIC-971A       (TW)
 	ktti    KT Technology PHd adapter              (SG)
@@ -133,10 +135,12 @@
 	MicroSolutions          8000t tape      pt      bpck
 	SyQuest			EZ, SparQ	pd	epat
 	Imation			Superdisk	pf	epat
+	Maxell                  Superdisk       pf      friq
 	Avatar			Shark		pd	epat
 	FreeCom			CD-ROM		pcd	frpw
 	Hewlett-Packard		5GB Tape	pt	epat
-	Hewlett-Packard		7100/7200	pg	epat
+	Hewlett-Packard		7200e (CD)	pcd	epat
+	Hewlett-Packard		7200e (CD-R)	pg	epat
 
 2.1  Configuring built-in drivers
 
@@ -315,7 +319,6 @@
 partitioned.  Consequently, the pf driver does not support partitioned
 media.  This may be changed in a future version of the driver. 
 
-
 2.5  Using the pt driver
 
 The pt driver for parallel port ATAPI tape drives is a minimal driver.
@@ -323,27 +326,29 @@
 For best performance, a block size of 32KB should be used.  You will
 probably want to set the parallel port delay to 0, if you can.
 
-
 2.6  Using the pg driver
 
 The pg driver can be used in conjunction with the cdrecord program
-to create CD-ROMs.  Please get cdrecord version 1.6.1a3 or later
-from ftp://ftp.fokus.gmd.de/pub/unix/cdrecord/ (you may have to look
-in the alpha subdirectory).  To record CD-R media your parallel port
-should ideally be set to EPP mode, and the "port delay" should be
-set to 0.  With those settings it is possible to record at 2x speed
-without any buffer underruns.  If you cannot get the driver to work
+to create CD-ROMs.  Please get cdrecord version 1.6.1 or later
+from ftp://ftp.fokus.gmd.de/pub/unix/cdrecord/ .  To record CD-R media 
+your parallel port should ideally be set to EPP mode, and the "port delay" 
+should be set to 0.  With those settings it is possible to record at 2x 
+speed without any buffer underruns.  If you cannot get the driver to work
 in EPP mode, try to use "bidirectional" or "PS/2" mode and 1x speeds only.
 
 
 3. Troubleshooting
 
+3.1  Use EPP mode if you can
+
 The most common problems that people report with the PARIDE drivers
 concern the parallel port CMOS settings.  At this time, none of the
 PARIDE protocol modules support ECP mode, or any ECP combination modes.
 If you are able to do so, please set your parallel port into EPP mode
 using your CMOS setup procedure.
 
+3.2  Check the port delay
+
 Some parallel ports cannot reliably transfer data at full speed.  To
 offset the errors, the PARIDE protocol modules introduce a "port
 delay" between each access to the i/o ports.  Each protocol sets
@@ -357,6 +362,25 @@
 read the comments at the beginning of the driver source files in
 linux/drivers/block/paride.
 
+3.3  Some drives need a printer reset
+
+There appear to be a number of "noname" external drives on the market
+that do not always power up correctly.  We have noticed this with some
+drives based on OnSpec and older Freecom adapters.  In these rare cases,
+the adapter can often be reinitialised by issuing a "printer reset" on
+the parallel port.  As the reset operation is potentially disruptive in 
+multiple device environments, the PARIDE drivers will not do it 
+automatically.  You can however, force a printer reset by doing:
+
+	insmod lp
+	rmmod lp
+
+If you have one of these marginal cases, you should probably build
+your paride drivers as modules, and arrange to do the printer reset
+before loading the PARIDE drivers. 
+
+3.4  Use the verbose option and dmesg if you need help
+
 While a lot of testing has gone into these drivers to make them work
 as smoothly as possible, problems will arise.  If you do have problems,
 please check all the obvious things first:  does the drive work in
@@ -384,6 +408,8 @@
 by e-mail to grant@torque.net, or join the linux-parport mailing list
 and post your report there.
 
+3.5  For more information or help
+
 You can join the linux-parport mailing list by sending a mail message
 to 
 		linux-parport-request@torque.net
diff -urN linux-2.0.37-pre3/Documentation/udma.txt linux-2.0.37-pre4/Documentation/udma.txt
--- linux-2.0.37-pre3/Documentation/udma.txt	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.37-pre4/Documentation/udma.txt	2003-08-15 15:04:28.000000000 -0700
@@ -0,0 +1,663 @@
+UDMA information for kernels 2.0.35+
+
+Version 0.4 - July 98
+by Andrew D. Balsa <andrebalsa@altern.org>
+
+If you are in a hurry, skip to the "How does one use UDMA support?" section.
+
+If you need troubleshooting advice, check the "Unreliable drive +
+motherboard + driver combination" section.
+
+Support for UDMA is based on previous work by Kim-Hoe Pang and Christian
+Brunner, posted on the Linux Kernel mailing list around September 1997.
+Additional code was provided by Michel Aubry (VIA support) and Andre Hedrick
+(support for various PCI UDMA controller cards). The code base is Mark
+Lord's triton.c driver.
+
+Check the Linux UDMA mini-HOWTO by Brion Vibber first! It is the only Linux
+specific document available on the subject.
+
+Technical references:
+a) The Intel 82371AB data sheet, available in PDF format.
+b) The SiS 5598 and 5591 data sheets, available in Microsoft Word format. :(
+c) The VIA 82C586, 82C586A and 82C586B data sheets, in PDF format.
+d) Small Form Factor document SFF 8038I v1.0. This is the original document
+   that describes the DMA mode 2 protocol. Available in PDF format.
+e) The ATA/ATAPI-4 Working Draft, revision 17. This is document
+   d1153r17.pdf (in PDF format), available from the main IDE technical
+   reference site, ftp://fission.dt.wdc.com/pub/standards. This draft
+   describes the Ultra DMA protocol and timings.
+
+A somewhat less technical, but still very informative document is the
+Enhanced IDE/Fast-ATA/ATA-2 FAQ, by John Wehman and Peter den Haan. Check
+the Web page at http://come.to/eide.  
+
+**************************************************************************
+
+Files changed
+-------------
+
+Here is the set of files from Linux kernels 2.0.32/2.0.34 modified to enable
+UDMA transfers on motherboard chipsets that support it. For each file, there
+is a small explanation of the changes.
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+The following changes do not affect performance or stability of the IDE
+driver in any way.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+/drivers/block/triton.c
+
+ - removed some Intel specific timing stuff. This should not affect
+driver operation or performance. This is the only file that is heavily
+modified; the Promise and Artop code is by Andre Hedrick, the VIA code
+by Michel Aubry.
+
+/drivers/block/ide.c
+
+ - added UDMA drive reporting during driver initialization, at the end
+of routine do_identify (single line mod).
+
+ - added data for SiS 5513 and VIA VP-1 chipset in routine probe_for_hwifs
+(single line mods). Each new UDMA capable chipset will have to be added to
+this list (a single line is needed each time). Notice that you don't even
+need the motherboard chipset's data sheets to find the needed information.
+You just have to identify the IDE controller. You can do this by checking
+/proc/pci, and then comparing the IDE controller signature with that
+available from the Linux kernel.
+
+As it stands in this patched version, routine probe_for_hwifs supports the
+following chipsets: Intel FX, HX, VX, TX, LX and SiS 5513 (which is
+integrated in the SiS 5571, 5598 and 5591 chips). The VIA-VP1
+chipset is supported for DMA mode 2 transfers, but compatibility has not
+been tested with this driver. The VIA MVP-3 is reported OK with UDMA.
+
+/drivers/block/ide.h
+
+ - added flag using_udma in struct ide_drive_s (single line mod). 
+
+Small changes to the tape and ide-floppy code, and additions to pci.h and
+pci.c for the extra PCI UDMA controller devices.
+
+
+Tested configurations
+---------------------
+
+UDMA support has been thoroughly tested on the following configurations:
+
+Intel TX motherboard, PCI bus at 33 and 37.5MHz. (ASUS TX-97E)
+
+SiS 5598 motherboards, PCI bus at 33 and 37.5MHz. (Chaintech P5-SDA; ASUS
+SP-97V at 33MHz only)
+
+IBM DeskStar 6.4Gb and 8.4Gb drives. Samsung UDMA hard disk proved
+unreliable under Linux _and_ Windows95 (so it was not a driver problem).
+Other UDMA drives not tested.
+
+libc5 and gcc2.7.2. Also tested under libc6 (RedHat 5.0).
+
+6x86MX processor running at 166MHz or 187.5MHz.
+
+DANGER: EIDE drives do not accept a PCI bus at 41.5MHz (83MHz / 2). Trying
+to run DMA Mode 2 or UDMA at these PCI bus clocks will result in crashes and
+loss of data. If your FSB runs at > 75MHz you MUST set the PCI bus for
+asynchronous 33MHz operation. YOU HAVE BEEN WARNED.
+
+Andre Hedrick Tests [IMPORTANT: those are SMP configurations]
+-------------------------------------------------------------
+
+Test I
+------
+
+Tyan Tomcat III bios v4.01 SMP Dual P5 200 w/ Artop AEC6210 w/ DMA2 drives
+
+Intel MultiProcessor Specification v1.4
+    Virtual Wire compatibility mode.
+OEM ID: OEM00000 Product ID: PROD00000000 APIC at: 0xFEE00000
+Processor #0 Pentium(tm) APIC version 17
+Processor #1 Pentium(tm) APIC version 17
+I/O APIC #2 Version 17 at 0xFEC00000.
+Processors: 2
+
+Linux version 2.0.34 (root@Zosma) (gcc version 2.8.1) #1 Mon Jun 8 16:40:25 CDT
+Booting processor 1 stack 00002000: Calibrating delay loop.. ok - 79.67
+BogoMIPSTotal of 2 processors activated (159.33 BogoMIPS).
+Starting kswapd v 1.4.2.2
+
+ide: DMA Bus Mastering IDE controller on PCI bus 0 function 57
+ide: ports are not enabled (BIOS)
+ide: AEC6210 ROM enabled but no address
+ide: UDMA Bus Mastering IDE controller on PCI bus 0 function 160
+ide: timings == 04010401
+    ide0: BM-DMA at 0x6700-0x6707
+    ide1: BM-DMA at 0x6708-0x670f
+hda: Maxtor 72004 AP, 1916MB w/128kB Cache, CHS=973/64/63, DMA
+hdb: Maxtor 71626 A, 1554MB w/64kB Cache, CHS=789/64/63, DMA
+hdc: IOMEGA ZIP 100 ATAPI, ATAPI FLOPPY drive
+hdd: HP COLORADO 5GB, ATAPI TAPE drive
+ide-tape: Sorry, DRQ types other than Accelerated DRQ
+ide-tape: are still not supported by the driver
+ide-tape: the tape is not supported by this version of the driver
+ide2: ports already in use, skipping probe
+ide0 at 0x6300-0x6307,0x6402 on irq 11
+ide1 at 0x6500-0x6507,0x6602 on irq 11 (shared with ide0)
+scsi0 : ncr53c8xx - revision 2.5f.1
+
+Test II
+-------
+
+SuperMicro P6DNF SMP Dual P6 233 w/ Artop AEC6210 and Promise Ultra33
+
+Intel MultiProcessor Specification v1.4
+    Virtual Wire compatibility mode.
+OEM ID: INTEL    Product ID: 440FX        APIC at: 0xFEE00000
+Processor #0 Pentium(tm) Pro APIC version 17
+Processor #1 Pentium(tm) Pro APIC version 17
+I/O APIC #2 Version 17 at 0xFEC00000.
+Processors: 2
+
+Linux version 2.0.34 (root@Orion) (gcc version 2.8.1) #1 Wed Jun 17 01:13:15 CDT 1998
+Booting processor 1 stack 00002000: Calibrating delay loop.. ok - 232.65 BogoMIPS
+Total of 2 processors activated (464.49 BogoMIPS).
+
+ide: Intel 82371 (single FIFO) DMA Bus Mastering IDE
+    Controller on PCI bus 0 function 57
+ide: ports are not enabled (BIOS)
+ide: AEC6210 ROM enabled at 0xfebf8000
+ide: PCI UDMA Bus Mastering IDE
+    Controller on PCI bus 0 function 160
+ide: timings == 04010401
+    ide0: BM-DMA at 0xef90-0xef97
+    ide1: BM-DMA at 0xef98-0xef9f
+hda: QUANTUM FIREBALL ST3.2A, 3079MB w/81kB Cache, CHS=782/128/63, UDMA
+hdb: QUANTUM FIREBALL ST6.4A, 6149MB w/81kB Cache, CHS=784/255/63, UDMA
+hdc: IOMEGA ZIP 100 ATAPI, ATAPI FLOPPY drive
+hdd: CD-ROM CDU611, ATAPI CDROM drive
+ide2: ports already in use, skipping probe
+ide0 at 0xeff0-0xeff7,0xefe6 on irq 10
+ide1 at 0xefa8-0xefaf,0xefe2 on irq 10 (shared with ide0)
+
+Test III
+--------
+
+Same kernel above but with Promise Ultra33
+
+ide: Intel 82371 (single FIFO) DMA Bus Mastering IDE
+    Controller on PCI bus 0 function 57
+ide: ports are not enabled (BIOS)
+ide: PDC20246 ROM enabled at 0xfebd0000
+ide: PCI UDMA Bus Mastering IDE
+    Controller on PCI bus 0 function 160
+ide: timings == 000003ee
+    ide0: BM-DMA at 0xef80-0xef87
+    ide1: BM-DMA at 0xef88-0xef8f
+hda: QUANTUM FIREBALL ST3.2A, 3079MB w/81kB Cache, CHS=782/128/63, UDMA
+hdb: QUANTUM FIREBALL ST6.4A, 6149MB w/81kB Cache, CHS=784/255/63, UDMA
+hdc: IOMEGA ZIP 100 ATAPI, ATAPI FLOPPY drive
+hdd: CD-ROM CDU611, ATAPI CDROM drive
+ide2: ports already in use, skipping probe
+ide0 at 0xeff0-0xeff7,0xefe6 on irq 10
+ide1 at 0xefa8-0xefaf,0xebe6 on irq 10 (shared with ide0)
+
+All tests cases yield this problem, IOMEGA ZIP 100 ATAPI FW 23.D
+I have a patch fix for 2.1.99->106 similar for FW 21.D drives.
+
+ide-floppy: hdc: I/O error, pc = 5a, key =  5, asc = 24, ascq =  0
+ide-floppy: Can't get drive capabilities
+
+Note that both AEC6210 and PDC20246 have onboard bios that auto-config.
+
+
+What UDMA support does
+----------------------
+
+        - It enables UDMA transfers on the Intel TX chipset.
+	- It enables DMA mode2 transfers on the SiS 5571 and VIA VP-1
+	  (82C586) chipsets.
+        - It enables DMA mode2 and UDMA mode2 transfers on the SiS 5598 and
+	  SiS 5591 chipsets, and the VIA VP3 and MVP-3.
+        - With single line mods for each new chipset, it will support any DMA
+	  mode2 and/or UDMA capable chipset compatible with document
+	  SFF 8038I v1.0.
+	- Supports a variety of PCI UDMA controller cards.
+
+
+Support for other chipsets
+--------------------------
+
+It is relatively easy to add support for other chipsets. Some chipsets are
+entirely integrated (e.g. the SiS 5598 chipset has various devices in a
+single chip), others are divided into a Northbridge (CPU to PCI circuitry,
+L2 cache control, etc) and Southbridge (PCI to IDE bus mastering interface,
+USB, etc). We are dealing here with the Southbridge, specifically with the
+IDE bus master PCI device. If the data sheet says the device is SFF 8038I
+v1.0 compatible, then the registers have a more or less standard layout and
+this driver should work with the below changes:
+
+1) Check that the chipset is correctly identified by /proc/pci. Search for
+the line that identifies a bus-mastering IDE controller device.
+
+2) If the chipset is not correctly identified (new chipsets are not in
+kernels up to 2.0.33), you will need to edit /include/linux/pci.h and
+/drivers/pci/pci.c. This is actually quite easy, requiring a single line in
+each of these files.
+
+3) Now add a single line to ide.c, in routine probe_for_hwifs.
+
+4) Test and report results; when troubleshooting, please check first that
+you have the latest BIOS for your motherboard. 
+
+
+HOW does UDMA mode2 work?
+-------------------------
+
+Well, actually, the excellent triton.c driver written by Mark Lord is a
+generic DMA transfer hard disk driver. It does not depend on any chipset
+feature or transfer mode (i.e. it will work with DMA mode 2, UDMA and other
+future DMA modes with little or no changes). BTW in late 2.1.x kernels the
+driver was renamed ide-dma.c, to indicate that it is independent of the
+chipset used.
+
+(Note: triton is the "old" name for the Intel FX chipset, for which Mark
+Lord wrote the driver initially.)
+
+The Intel chipset specific parts were slightly changed in the triton.c
+driver. These are only used to gather information for driver testing, and
+actually do not affect the operation or performance of the driver, so the
+changes are (well, should be) relatively inocuous.
+
+The real work involved in setting up the chips for DMA transfers is done
+mostly by the BIOS of each motherboard. Now of course one hopes that the
+BIOS has been correctly programmed...
+
+For example, the ASUS SP-97V motherboard with its original BIOS (Rev. 1.03)
+would malfunction with the modified Linux driver in both DMA mode 2 and UDMA
+modes; it would work well using PIO mode 4, or under Windows 95 in all
+modes. I downloaded the latest BIOS image (Rev. 1.06) from the ASUS Web site
+and flashed the BIOS EPROM with the latest BIOS revision. It has been
+working perfectly ever since (at 66 MHz bus speeds).
+
+What this tells us is that the BIOS sets up the DMA controller with specific
+timing parameters (active pulse and recovery clock cycles). My initial BIOS
+revision probably had bad timings. Since the Windows 95 driver sets up those
+timings by itself (i.e. it does not depend on the BIOS to setup the hard
+disk controller timing parameters), I initially had problems only with the
+Linux driver, while Windows 95 worked well.
+
+So, let me state this again: this Linux (U)DMA driver depends on the BIOS for
+correct (U)DMA controller setup. If you have problems, first check that you
+have the latest BIOS revision for your specific motherboard.
+
+OTOH Michel Aubry's code for the VIA Apollo chipset has complete support for
+setting up the timing parameters. Check the triton.c source code for
+details.
+
+New BIOS revisions can be downloaded from your motherboard manufacturer's
+Web site. Flashing a new BIOS image is a simple operation but one must
+strictly follow the steps explained on the motherboard manual.
+
+Late Award BIOS revisions seem stable with respect to UDMA. Anything with a
+date of 1998 should be fine.
+
+
+Features missing from the present UDMA support code
+---------------------------------------------------
+
+It does not set UDMA transfer parameters (the driver assumes the BIOS has
+correctly setup all timing parameters) in the various chipsets. This
+requires access to a complete set of data sheets for the various chipsets,
+and testing on a variety of configurations, so it's not exactly within the
+reach of a humble Linux hacker. IMHO this is best left to the guys at Award
+and AMI (the BIOS guys), and to the motherboard engineers.
+
+Basically, UDMA transfers depend on two timing parameters:
+	1) The pulse width of the active strobe signal for data transfers
+(usually described as the active pulse width).
+	2) The delay between the negation of the DMA READY signal to the
+assertion of STOP when the IDE controller wants to stop a read operation
+(usually described as the recovery time).
+
+Both timing parameters can be set individually for each hard disk (up to two
+hard disks per channel).
+
+Knowing which registers must hold this data and the appropriate values, one
+could program the Linux triton.c driver to setup the IDE controller device,
+without relying on BIOS settings. However, some chipsets allow setting other
+timing parameters, and the required code would quickly increase to a
+not-so-easy-to-manage size. Better keep it simple, IMHO.
+
+It seems Mark Lord has devised a neat way to do this in the ide-dma driver
+included in late kernels 2.1.x: each chipset has an entry in a table, with
+safe timing values. The chipset is also identified when the driver is
+loaded.
+
+
+How does one use UDMA support?
+------------------------------
+
+1) Backup your data or you will be sorry. Now do "hdparm -t -T
+/dev/hda". Write a small note with the transfer rates you see.
+
+2) Reboot. Press [Del] to launch the CMOS SETUP routine, go to the
+CHIPSET SPECIFIC or PERIPHERALS SETUP menus, and enable UDMA transfers
+for your hard disk drives which are UDMA capable, or leave the fields in
+the default "AUTO" value. Enable both IDE channels even if you have just
+one IDE drive (default setting).
+
+3) Boot Linux, compile the kernel with the TRITON support enabled. Install
+the new kernel (the lilo thingy). Reboot Linux.
+
+4) Watch for the drive parameters message when the kernel loads (or type
+"dmesg | more" after login). After the Cyl, Heads, Sect parameters you
+should see "DMA" or "UDMA" depending on your hard disk drive and chipset
+capabilities.
+
+Here is what I get with UDMA enabled in the BIOS of my SiS 5598 based
+configuration, with an IBM UDMA capable hard disk as hda:
+
+...
+ide: DMA Bus Mastering IDE controller on PCI bus 0 function 9
+    ide0: BM-DMA at 0x4000-0x4007
+    ide1: BM-DMA at 0x4008-0x400f
+hda: IBM-DHEA-36480, 6197MB w/476kB Cache, LBA, CHS=790/255/63, UDMA
+...
+
+If I disable UDMA in the BIOS, I get:
+
+...
+ide: DMA Bus Mastering IDE controller on PCI bus 0 function 9
+    ide0: BM-DMA at 0x4000-0x4007
+    ide1: BM-DMA at 0x4008-0x400f
+hda: IBM-DHEA-36480, 6197MB w/476kB Cache, LBA, CHS=790/255/63, DMA
+...
+
+5) Again, do "hdparm -t -T /dev/hda". Smile. Test your setup by copying
+a few large files around or doing some large compilation (e.g. the Linux
+kernel itself).
+
+
+Performance issues
+------------------
+
+1) Sustained transfer rates.
+
+Here is some data gathered after extensive testing, using the hdparm utility
+(also written by Mark Lord):
+
+PIO mode 4 transfer rates under Linux:   +/- 5.2MB/s
+
+DMA mode 2 transfer rates under Linux:   +/- 7.2MB/s
+
+UDMA mode 2 transfer rates under Linux:  +/- 9.8MB/s
+
+Data gathered on a Chaintech SiS 5598 motherboard, 6x86MX @ 187.5MHz, Linux
+2.0.32/2.0.33 with patched triton.c driver as explained above, IBM DeskStar
+6.4GB hard disk (IBM-DHEA-36480).
+
+The integrated video hardware in the SiS 5598 chip was disabled (a standard
+PCI video board was used); enabling the integrated SVGA controller will
+cause a 20% performance hit in processing performance, due to limited main
+memory bandwidth.
+
+The TX motherboard under the same test conditions will be slightly
+slower (0.1 - 0.2 MB/s slower).
+
+Burst (instantaneous) transfer rates are supposed to go from 16.6MB/s (PIO
+mode 4) to 16.6MB/s (DMA mode 2) up to 33MB/s (UDMA). In his patch against
+kernel 2.1.55, Kim-Hoe Pang actually checked the UDMA burst transfer rate
+with a logic analiser: 60ns/word, which translates into 33MB/s.
+
+Note that burst transfer rates only affect data transfers to/from the EIDE
+drive cache (476kB for the IBM 6.4GB drive), and IMHO are not particularly
+relevant for most Linux users.
+
+The Linux kernel uses as much RAM as possible to cache hard disk data
+accesses, and so if data is not in the kernel cache there is little chance
+that it will be in the (much smaller) hard disk cache.
+
+2) Processor utilization
+
+Unfortunately, it is very difficult to gather data about processor
+utilization during data transfers, but this is exactly the biggest advantage
+of DMA transfers over PIO transfers. My estimate is that CPU utilization
+during UDMA transfers will be as low as 3-4%, while being somewhere around
+30% for PIO transfers and 6-8% for DMA mode 2.
+
+3) UDMA vs SCSI
+
+The main advantage of DMA mode 2 and UDMA over SCSI is that the controller
+is already on your motherboard, so why not use it?
+
+Mark Lord's triton.c driver has a very small latency and so UDMA drives
+may beat their Ultra-Wide SCSI-2 counterparts in some cases (at equal
+spindle speeds) e.g. lots of small files (loaded news servers) being
+read/written at irregular intervals.
+
+Note however that SCSI drives are available at spindle speeds of 7,200,
+10,000 and even a recently announced 12,030 rpm. IBM is planning some 7,200
+rpm UDMA EIDE drives, but those are not yet available. Seagate has just
+released its EIDE 7,200 rpm drives, but they have special cooling
+requirements just like their SCSI counterparts. Expect this technology to
+become commonplace by the end of 98, though.
+
+The UDMA burst data transfer rates exceed maximum head transfer rates
+(maximum head transfer rates in the industry have reached 160 Mbits/s in
+1998) and so for large files neither Ultra-Wide SCSI-2 nor UDMA will have an
+advantage over the other technology.
+
+It used to be that high-capacity drives were only available with SCSI
+interfaces, but this isn't true anymore. Right now top capacity for an EIDE
+drive is Maxtor's 11.3Gb monster, which is quite affordable in fact. One can
+drive four of these with a standard motherboard: 45Gb for < $2k.
+
+SCSI drives can chain, overlap and re-order commands, EIDE drives cannot.
+However, Linux already has an intelligent "elevator" algorithm for hard disk
+accesses.
+
+At present, EIDE top speed is 33MB/s burst. Ultra-Wide II SCSI is 80MB/s
+burst. The cost of an Ultra-Wide II SCSI controller + 9Gb hard disk is > 4 x
+the cost of an 8GB UDMA drive. IMHO the price/performance ratio of UDMA
+beats SCSI.
+
+A new standard is emerging called ATA-66, which will double the burst
+transfer speed of EIDE drives to 66Mb/s. I don't have any technical info
+about it, unfortunately. The first ATA-66 drives will be shipped by Quantum
+in 1999, but VIA has already announced two ATA-66 capable chipsets (in fact
+based on the same Southbridge chip); as I write this, data sheets are not
+available to the general public. Probably Intel will come out with a chipset
+of its own with ATA-66 capabilities.
+
+4) What is the best UDMA chipset/hard disk?
+
+Intel designed the first DMA mode 2 capable chipset, the FX (Triton I) a few
+years ago. The Linux DMA mode 2 driver was initially written by Mark Lord
+for the original Intel FX chipset and appeared around kernel 1.3.20 if I
+remember well. The later HX and VX chipsets had exactly the same DMA mode 2
+capabilities and the triton.c driver was for a long time Intel-only. Mark
+planned to support the Opti Viper chipset but Opti went out of the
+motherboard chipset business so fast that Mark didn't even have the time to
+get his hands on an Opti motherboard, I guess.
+
+Intel later introduced a UDMA compatible motherboard chipset with its TX
+chipset. Kernel 2.0.31 was the first Linux kernel to support the TX chipset,
+however only DMA mode 2 (16.6MB/s) was supported.
+
+The TX chipset has a proven record of reliability. But DMA mode 2 and UDMA
+transfers on the TX suffer from a flaw common to previous Intel DMA mode 2
+only chipsets: a single data buffer is shared between the two IDE channels.
+This buffer (64 bytes deep) is used to hold data on its way from the PCI bus
+to/from the hard disk's small cache. A hardware arbitration mechanism
+prevents data loss when the OS tries to simultaneously use both IDE
+channels.
+
+VIA chips also have a single FIFO, with the same 64 bytes deep buffer.
+However, VIA chips can have the buffer split 1:1 or 3:1 between both IDE
+channels; an interesting feature, but difficult to use.
+
+How is this FIFO buffer used? Remember that the PCI bus can transfer data at
+a maximum rate of 132MB/s when clocked at 33MHz, 150MB/s when clocked at
+37.5MHz (maximum safe clock speed for PCI is 33MHz, after that well..). So the
+PCI bus mastering IDE controller will be transfering data from main memory
+DRAM to this FIFO buffer in small bursts of < 64 bytes, then from the buffer
+to the IDE disk drive cache (when writing; the other way around for reads).
+
+I recently managed to get hold of the SiS 5598 data sheet and studied the
+IDE controller part of this highly integrated chip, a device identified by
+the number 5513. The 5598 even includes an SVGA controller, which should be
+disabled if one wants to get decent performance from this chipset: it
+severely limits CPU/memory bandwidth. The SiS5597 is the same part with
+a different pinout.
+
+It appears the 5513 has two completely independent IDE channels, each with
+its own 64 bytes deep data buffer. On disk-to-disk or CD-to-disk transfers,
+the 5598 and 5591 chipsets will easily beat the Intel TX and VIA. On
+simultaneous (U)DMA transfers to two disks (for example, when the Linux md
+driver is used to create a RAID-0 array with data striping), the 5513 device
+will be faster than the TX Southbridge device since there will be no
+contention for the data buffer, assuming each drive is connected to a
+different IDE channel.  Other PCI bus related features will also improve its
+performance of the SiS devices. So, compared to the Intel TX and various VIA
+chipsets, the 5598 and 5591 win hands down in terms of UDMA implementation.
+
+Unfortunately, it is very difficult to get data sheets for the ALi Aladdin
+IV+ and Aladdin V chipsets. These newer chipsets support up to 1 MB of L2
+SRAM cache, the AGP bus (2X), 100 MHz CPU bus and of course, UDMA data
+transfers. The newest VIA chipset for Socket 7 motherboards beats them all
+in terms of features, as it sports ATA-66 compatibility.
+
+On the UDMA hard drive front, the present performance leaders are the IBM
+Deskstar drives. These drives have relatively large data caches (476kB
+available), a 5,400 rpm rotational speed and < 10ms random access times.
+They run very cool and although they can't be called silent, their noise
+level is acceptable. They are also reliable.
+
+Seagate has just begun shipping 7,200 rpm EIDE drives which will obviously
+benefit from the lower data latency. They are reported as particularly
+silent due to the use of Fluid Dynamic Bearing motors, but running quite
+hot. IMHO if one has to add a fan to cool them, this defeats any advantage
+these drives will have in terms of noise level. Another advantage of this
+technology is the lower vibration levels compared to ball bearings.
+
+IBM has pre-announced very large capacity (14GB), 7,200 rpm EIDE UDMA drives
+a month ago, but those are not shipping yet. They are based on a new head
+technology called Giant Magneto-Resistive Heads, which is supposed to
+increase the data density on the disks by a factor of 4 or more. More details
+when I get my hands on one. IBM licensed Western Digital to use this
+technology.
+
+Quantum has always shipped among the best and fastest EIDE drives, and they
+worked with Intel to create the UDMA standard. They used to have the fastest
+drives for Linux DMA mode 2 transfers (see the comments in
+/Documentation/ide.txt).
+
+Well, I just got an email from Denny de Jonge <denny@luna.nl> that proves
+Quantum drives will keep their reputation:
+
+"Andre,
+
+ After I applied the UDMA-patch for Linux 2.0.33 hdparm showed up with the
+ following benchmarks:
+
+ /dev/hda:
+
+ Timing buffer-cache reads:   64 MB in  1.02 seconds =62.75 MB/sec
+ Timing buffered disk reads:  32 MB in  3.02 seconds =10.60 MB/sec
+
+ Not bad, don't you think ?
+
+ These results have been obtained using the Intel 82371 Chipset and a
+ Quantum Fireball 4.3SE harddisk."
+
+I later asked what kind of processor Denny was using: it's a 266MHz PII.
+
+BTW I have been collecting hard disk/file subsystem benchmarking information
+based on bonnie, a popular benchmark available for Linux. I have come to the
+conclusion that bonnie is not a reliable benchmark when it comes to
+comparing different systems, basically because it depends so much on how
+much RAM one has installed and how much of it is free, as well as system
+load, CPU speed, etc. For this reason I will not quote bonnie results
+anymore. For comparative benchmarking between two hard disk drives on
+exactly the same hardware it may be acceptable, but otherwise it's too
+unreliable as an indicator of performance.
+
+
+Unreliable drive + motherboard + driver combination
+---------------------------------------------------
+
+Quoting Kim-Hoe Pang:
+
+"The UDMA mode of an UDMA drive would NOT be enabled on a non-UDMA capable
+chipset mobo. On power-up or after a hardware reset, the drive is in normal
+PIO/DMA mode. To enable the UDMA mode in the drive, the host, BIOS or OS,
+needs to send a SET FEATURE ("enable UDMA mode subcommand") AT command to
+the drive. A non-UDMA capable mobo will not send this command to the drive.
+
+UDMA mode is dis/enabled via BIOS setup. The patch does not attempt to
+override user's BIOS setting."
+
+There may be some combinations of drives, motherboards (BIOS) and Linux
+driver which may prove unreliable. Remember we are transfering data at
+33MB/s over unshielded ribbon cable in a very noisy (electromagnetically
+speaking) environment.
+
+In the future it would be nice if hard disk manufacturers would publish the
+timings required by their drives, and chipset manufacturers would follow a
+single standard for registers and controller architecture. Right now UDMA is
+extremely timing sensitive.
+
+A few recommendations for troubleshooting:
+
+1) Make sure you have the latest BIOS for your motherboard. Connect to the
+motherboard manufacturer's Web site and download the latest BIOS image file
+and EEPROM flashing utilities. Check your BIOS version, and only flash your
+EEPROM if needed.
+
+2) Keep the IDE cable going from the motherboard to the drive short, and do
+not loop it around another cable. I recommend < 30 cm (12") total cable
+length.
+
+3) If you have just a single UDMA hard disk drive per channel (which I
+recommend), use the connectors at both ends of the cable to connect
+motherboard and drive, do _not_ use the middle connector. If you have a UDMA
+hard disk drive and a CD-ROM drive on the same cable, plug the hard disk
+drive at the end of the cable (use the middle connector for the CD-ROM
+drive). Also the hard disk must be the master EIDE device, the CD-ROM drive
+the slave EIDE device, never the other way around (this is not determined by
+cable position, but by small jumpers on the drive and at the back of the
+CD-ROM). The same rules apply to CD-RW, ZIP and tape EIDE drives.
+
+4) If you have (shudder) Windows 95 installed in your system, and have been
+able to use UDMA, you should be able to use UDMA with Linux.
+
+5) DON'T OVERCLOCK the PCI bus. 33MHz is the maximum supported speed for
+the PCI bus. Some (supposedly compatible) UDMA drives will not even take
+37.5MHz, but should be OK at 33.3MHz.
+
+In any case, NEVER, NEVER set the PCI bus to 41.5MHz.
+
+The RECOMMENDED safe setting is 33MHz.
+
+Adequate testing is needed in each case. The golden rule here, as always:
+backup, backup, backup.
+
+
+Aknowledgments
+--------------
+
+Mark Lord for his excellent, reliable and very readable triton.c driver code
+and all his (E)IDE Linux programming.
+
+Kim-Hoe Pang for the first UDMA patch against kernel 2.1.55.
+
+Christian Brunner for his patch converting triton.c into a generic DMA mode
+2 EIDE driver. 
+
+Brion Vibber for his neat Linux UDMA mini-HOWTO, for his help and
+contributions to this package, and for bearing with my various documentation
+changes and suggestions.
+
+Michel Aubry for his complete VIA support and neat diagnostics code, as well
+as the patch to hdparm to support UDMA.
+
+Andre Hedrick for his great code for the various PCI UDMA controller cards.
+
diff -urN linux-2.0.37-pre3/drivers/block/Config.in linux-2.0.37-pre4/drivers/block/Config.in
--- linux-2.0.37-pre3/drivers/block/Config.in	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/block/Config.in	2003-08-15 15:04:28.000000000 -0700
@@ -23,6 +23,9 @@
   if [ "$CONFIG_PCI" = "y" ]; then
     bool '   RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000
     bool '   Intel 82371 PIIX (Triton I/II) DMA support' CONFIG_BLK_DEV_TRITON
+    if [ "$CONFIG_BLK_DEV_TRITON" = "y" ]; then
+      bool '     Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
+    fi
   fi
   bool '   Other IDE chipset support' CONFIG_IDE_CHIPSETS
   if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
@@ -57,6 +60,8 @@
   bool 'Mylex DAC960 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960
 fi
 
+tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA
+
 tristate 'Parallel port IDE device support' CONFIG_PARIDE 
 if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then
   source drivers/block/paride/Config.in
diff -urN linux-2.0.37-pre3/drivers/block/cpqarray.c linux-2.0.37-pre4/drivers/block/cpqarray.c
--- linux-2.0.37-pre3/drivers/block/cpqarray.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.37-pre4/drivers/block/cpqarray.c	2003-08-15 15:04:28.000000000 -0700
@@ -0,0 +1,1543 @@
+/*
+ *    Disk Array driver for Compaq SMART2 Controllers
+ *    Copyright 1998 Compaq Computer Corporation
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *    NON INFRINGEMENT.  See the GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ *    If you want to make changes, improve or add functionality to this
+ *    driver, you'll probably need the Compaq Array Controller Interface
+ *    Specificiation (Document number ECG086/1198)
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/timer.h>
+#include <linux/proc_fs.h>
+#include <linux/hdreg.h>
+#include <asm/io.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+extern struct inode_operations proc_diskarray_inode_operations;
+
+#define DRIVER_NAME "Compaq SMART2 Driver (v 0.9.5)"
+
+#define MAJOR_NR COMPAQ_SMART2_MAJOR
+#include <linux/blk.h>
+#include <linux/blkdev.h>
+#include <linux/genhd.h>
+
+#include "cpqarray.h"
+#include "ida_cmd.h"
+#include "ida_ioctl.h"
+
+#define READ_AHEAD	128
+
+#define MAX_CTLR	8
+#define CTLR_SHIFT	8
+
+static int nr_ctlr = 0;
+static ctlr_info_t *hba[MAX_CTLR] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+static struct hd_struct * ida;
+static int * ida_sizes;
+static int * ida_blocksizes;
+static int * ida_hardsizes;
+static int * ida_maxsectors;
+static int * ida_maxsegments;
+static struct gendisk ida_gendisk[MAX_CTLR];
+
+
+/* Debug... */
+#define DBG(s)	s
+/* Debug (general info)... */
+#define DBGINFO(s)
+/* Debug Paranoid... */
+#define DBGP(s) s
+/* Debug Extra Paranoid... */
+#define DBGPX(s)
+
+#undef PROFILE_REQUESTS
+#ifdef PROFILE_REQUESTS
+#define PF_REQ_SCALE	200000000UL
+#endif /* PROFILE_REQUESTS */
+
+
+#define PROFILE_MEMUSAGE
+#ifdef PROFILE_MEMUSAGE
+unsigned int nr_allocs = 0;
+unsigned int nr_frees = 0;
+#endif
+
+void cpqarray_init(void);
+static int cpqarray_pci_detect(void);
+static void cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn);
+static ulong remap_pci_mem(ulong base, ulong size);
+static void flushcomplete(int ctlr);
+static int pollcomplete(int ctlr);
+static void getgeometry(int ctlr);
+
+static cmdlist_t * cmd_alloc(int intr);
+static void cmd_free(cmdlist_t *c);
+
+static int sendcmd(
+	__u8	cmd,
+	int	ctlr,
+	void	*buff,
+	size_t	size,
+	unsigned int blk,
+	unsigned int blkcnt,
+	unsigned int log_unit );
+
+static int ida_open(struct inode *inode, struct file *filep);
+static void ida_release(struct inode *inode, struct file *filep);
+static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg);
+static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io);
+
+static void do_ida_request(int i);
+/*
+ * This is a hack.  This driver eats a major number for each controller, and
+ * sets blkdev[xxx].request_fn to each one of these so the real request
+ * function knows what controller its working with.
+ */
+#define DO_IDA_REQUEST(x) { \
+	int flags; save_flags(flags); cli(); \
+	do_ida_request(x); restore_flags(flags); }
+
+static void do_ida_request0(void) DO_IDA_REQUEST(0);
+static void do_ida_request1(void) DO_IDA_REQUEST(1);
+static void do_ida_request2(void) DO_IDA_REQUEST(2);
+static void do_ida_request3(void) DO_IDA_REQUEST(3);
+static void do_ida_request4(void) DO_IDA_REQUEST(4);
+static void do_ida_request5(void) DO_IDA_REQUEST(5);
+static void do_ida_request6(void) DO_IDA_REQUEST(6);
+static void do_ida_request7(void) DO_IDA_REQUEST(7);
+
+static void start_io(ctlr_info_t *h);
+
+static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c);
+static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c);
+static inline void complete_buffers(struct buffer_head *bh, int ok);
+static inline void complete_command(cmdlist_t *cmd, int timeout);
+
+static void do_ida_intr(int irq, void *dev_id, struct pt_regs * regs);
+static void ida_timer(unsigned long tdata);
+static int frevalidate_logvol(kdev_t dev);
+static int revalidate_logvol(kdev_t dev, int maxusage);
+static int revalidate_allvol(kdev_t dev);
+
+static void ida_procinit(int i);
+static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int dp);
+
+
+void ida_geninit(struct gendisk *g)
+{
+	int ctlr = g-ida_gendisk;
+	int i,j;
+	drv_info_t *drv;
+
+	for(i=0; i<NWD; i++) {
+		drv = &hba[ctlr]->drv[i];
+		if (!drv->nr_blks)
+			continue;
+		ida[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)].nr_sects =
+		ida_sizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)] =
+				drv->nr_blks;
+
+		for(j=0; j<16; j++) {
+			ida_blocksizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)+j] =
+				1024;
+			ida_hardsizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)+j] =
+				drv->blk_size;
+		}
+		ida_gendisk[ctlr].nr_real++;
+	}
+
+}
+
+struct file_operations ida_fops  = {
+	NULL,                        /* lseek - default */
+	block_read,                  /* read - general block-dev read */
+	block_write,                 /* write - general block-dev write */
+	NULL,                        /* readdir - bad */
+	NULL,                        /* select */
+	ida_ioctl,                  /* ioctl */
+	NULL,                        /* mmap */
+	ida_open,                     /* open code */
+	ida_release,                  /* release */
+	block_fsync,	              /* fsync */
+	NULL,                        /* fasync */
+	NULL,			/* Disk change */
+	frevalidate_logvol,	/* revalidate */
+};
+
+
+/*
+ * Get us a file in /proc that says something about each controller.  Right
+ * now, we add entries to /proc, but in the future we should probably get
+ * our own subdir in /proc (/proc/array/ida) and put our stuff in there.
+ */
+struct proc_dir_entry *proc_array = NULL;
+static void ida_procinit(int i)
+{
+	struct proc_dir_entry *pd;
+
+	if (proc_array == NULL) {
+		proc_array = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
+		if (!proc_array) return;
+		memset(proc_array, 0, sizeof(struct proc_dir_entry));
+		proc_array->namelen = 5;
+		proc_array->name = "array";
+		proc_array->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+		proc_array->nlink = 2;
+		proc_array->uid = 0;
+		proc_array->gid = 0;
+		proc_array->size = 0;
+		proc_array->ops = &proc_dir_inode_operations;
+		proc_register_dynamic(&proc_root, proc_array);
+	}
+
+	pd = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
+	if (!pd) return;
+	memset(pd, 0, sizeof(struct proc_dir_entry));
+	pd->namelen = 4;
+	pd->name = hba[i]->devname;
+	pd->mode = S_IFREG | S_IRUGO;
+	pd->nlink = 1;
+	pd->uid = 0;
+	pd->gid = 0;
+	pd->size = 0;
+	pd->ops = &proc_diskarray_inode_operations;
+	pd->get_info = ida_proc_get_info;
+	
+	hba[i]->proc = (int)pd;
+	proc_register_dynamic(proc_array, pd);
+}
+
+/*
+ * Report information about this controller.
+ */
+static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int pd)
+{
+	off_t pos = 0;
+	off_t len = 0;
+	int size, i, ctlr;
+	ctlr_info_t *h;
+	drv_info_t *drv;
+#ifdef CPQ_PROC_PRINT_QUEUES
+	cmdlist_t *c;
+#endif
+
+	for(ctlr=0; ctlr<nr_ctlr; ctlr++) 
+		if (hba[ctlr] && hba[ctlr]->proc == pd) break;
+
+
+	if ((h = hba[ctlr]) == NULL)
+		return 0;
+
+	size = sprintf(buffer, "%s:  Compaq SMART/2 Disk Array Controller\n"
+		"       Board ID: %08lx\n"
+		"       Firmware Revision: %08lx\n"
+		"       Controller Sig: %08lx\n"
+		"       Memory Address: %08lx\n"
+		"       I/O Port: %04x\n"
+		"       IRQ: %x\n"
+		"       Logical drives: %d\n"
+		"       Physical drives: %d\n\n"
+		"       Current Q depth: %d\n"
+		"       Max Q depth: %d\n"
+		"       Max Q depth since init: %d\n\n",
+		h->devname, (unsigned long)h->board_id,
+		(unsigned long)h->firm_rev,
+		(unsigned long)h->ctlr_sig, (unsigned long)h->vaddr,
+		(unsigned int) h->ioaddr, (unsigned int)h->intr,
+		h->log_drives, h->phys_drives,
+		h->Qdepth, h->maxQ, h->maxQsinceinit);
+
+	pos += size; len += size;
+	
+	size = sprintf(buffer+len, "Logical Drive Info:\n");
+	pos += size; len += size;
+
+	for(i=0; i<h->log_drives; i++) {
+		drv = &h->drv[i];
+		size = sprintf(buffer+len, "ida/c%dd%d: blksz=%d nr_blks=%d\n",
+				ctlr, i, drv->blk_size, drv->nr_blks);
+		pos += size; len += size;
+	}
+
+#ifdef CPQ_PROC_PRINT_QUEUES
+	size = sprintf(buffer+len, "\nCurrent Queues:\n");
+	pos += size; len += size;
+
+	c = h->reqQ;
+	size = sprintf(buffer+len, "reqQ = %p", c); pos += size; len += size;
+	if (c) c=c->next;
+	while(c && c != h->reqQ) {
+		size = sprintf(buffer+len, "->%p", c);
+		pos += size; len += size;
+		c=c->next;
+	}
+
+	c = h->cmpQ;
+	size = sprintf(buffer+len, "\ncmpQ = %p", c); pos += size; len += size;
+	if (c) c=c->next;
+	while(c && c != h->cmpQ) {
+		size = sprintf(buffer+len, "->%p", c);
+		pos += size; len += size;
+		c=c->next;
+	}
+
+	size = sprintf(buffer+len, "\n"); pos += size; len += size;
+#endif
+#ifdef PROFILE_REQUESTS
+	size = sprintf(buffer+len,
+			"Request latencies (min/avg/max) = (%d, %d, %d) %d requests\n",
+			(h->min_latency),
+			(h->avg_latency),
+			(h->max_latency),
+			h->nr_requests);
+	pos += size; len += size;
+#endif /* PROFILE_REQUESTS */
+#ifdef PROFILE_MEMUSAGE
+	size = sprintf(buffer+len,"nr_allocs = %d\nnr_frees = %d\n",
+			nr_allocs, nr_frees);
+	pos += size; len += size;
+#endif /* PROFILE_MEMUSAGE */
+
+	*start = buffer+offset;
+	len -= offset;
+	if (len>length)
+		len = length;
+	return len;
+}
+
+#ifdef MODULE
+/* This is a hack... */
+#include "proc_array.c"
+int init_module(void)
+{
+	int i, j;
+	cpqarray_init();
+	if (nr_ctlr == 0)
+		return -EIO;
+
+	for(i=0; i<nr_ctlr; i++) {
+		ida_geninit(&ida_gendisk[i]); 
+		for(j=0; j<NWD; j++)	
+			if (ida_sizes[(i<<CTLR_SHIFT) + (j<<NWD_SHIFT)])
+				resetup_one_dev(&ida_gendisk[i], j);
+	}
+	return 0;
+}
+void cleanup_module(void)
+{
+	int i;
+	struct gendisk *g;
+
+	for(i=0; i<nr_ctlr; i++) {
+		writel(0, hba[i]->vaddr + INTR_MASK);
+		free_irq(hba[i]->intr, hba[i]);
+		vfree((void*)hba[i]->vaddr);
+		unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
+		proc_unregister(proc_array,
+			((struct proc_dir_entry*)hba[i]->proc)->low_ino);
+		del_timer(&hba[i]->timer);
+
+		if (gendisk_head == &ida_gendisk[i]) {
+			gendisk_head = ida_gendisk[i].next;
+		} else {
+			for(g=gendisk_head; g; g=g->next) {
+				if (g->next == &ida_gendisk[i]) {
+					g->next = ida_gendisk[i].next;
+					break;
+				}
+			}
+		}
+
+		blk_dev[MAJOR_NR+i].request_fn = NULL;
+		blksize_size[MAJOR_NR+i] = NULL;
+		hardsect_size[MAJOR_NR+i] = NULL;
+		max_sectors[MAJOR_NR+i] = NULL;
+		max_segments[MAJOR_NR+i] = NULL;
+	}
+	proc_unregister(&proc_root, proc_array->low_ino);
+	kfree(ida);
+	kfree(ida_sizes);
+	kfree(ida_hardsizes);
+	kfree(ida_blocksizes);
+
+	kfree(ida_maxsectors);
+	kfree(ida_maxsegments);
+
+}
+#endif /* MODULE */
+
+/*
+ *  This is it.  Find all the controllers and register them.  I really hate
+ *  stealing all these major device numbers.
+ */
+void cpqarray_init(void)
+{
+	void (*request_fns[MAX_CTLR])(void) = {
+		do_ida_request0, do_ida_request1,
+		do_ida_request2, do_ida_request3,
+		do_ida_request4, do_ida_request5,
+		do_ida_request6, do_ida_request7,
+	};
+	int i;
+
+	/* detect controllers */
+	if (cpqarray_pci_detect() == 0)
+		return;
+
+	printk(DRIVER_NAME "\n");
+	printk("Found %d controller(s)\n", nr_ctlr);
+
+	/* allocate space for disk structs */
+	ida = kmalloc(sizeof(struct hd_struct)*nr_ctlr*NWD*16, GFP_KERNEL);
+	ida_sizes =      kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
+	ida_blocksizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
+	ida_hardsizes =  kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
+
+	ida_maxsegments =  kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
+	ida_maxsectors =  kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
+
+	memset(ida, 0, sizeof(struct hd_struct)*nr_ctlr*NWD*16);
+	memset(ida_sizes, 0, sizeof(int)*nr_ctlr*NWD*16);
+	memset(ida_blocksizes, 0, sizeof(int)*nr_ctlr*NWD*16);
+	memset(ida_hardsizes, 0, sizeof(int)*nr_ctlr*NWD*16);
+	memset(ida_maxsegments, 0, sizeof(int)*nr_ctlr*NWD*16);
+	memset(ida_maxsectors, 0, sizeof(int)*nr_ctlr*NWD*16);
+	memset(ida_gendisk, 0, sizeof(struct gendisk)*MAX_CTLR);
+
+	for(i=0; i<nr_ctlr*NWD*16; i++) {
+		ida_maxsegments[i] = SG_MAX;
+		ida_maxsectors[i] = 1024;
+	}
+	/* 
+	 * register block devices
+	 * Find disks and fill in structs
+	 * Get an interrupt, set the Q depth and get into /proc
+	 */
+	for(i=0; i< nr_ctlr; i++) {
+		writel(0, hba[i]->vaddr + INTR_MASK);  /* No interrupts */
+		if (request_irq(hba[i]->intr, do_ida_intr,
+			SA_INTERRUPT | SA_SHIRQ, hba[i]->devname, hba[i])) {
+
+			printk("Unable to get irq %d for %s\n",
+				hba[i]->intr, hba[i]->devname);
+			continue;
+		}
+		if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) {
+			printk("Unable to get major number %d for %s\n",
+				MAJOR_NR+i, hba[i]->devname);
+			continue;
+		}
+
+		printk("Finding drives on %s\n", hba[i]->devname);
+		getgeometry(i);
+
+		writel(FIFO_NOT_EMPTY, hba[i]->vaddr + INTR_MASK);
+
+		hba[i]->maxQ = 32;
+#ifdef PROFILE_REQUESTS
+		hba[i]->min_latency=0xffffffff;
+#endif
+		ida_procinit(i);
+
+		ida_gendisk[i].major = MAJOR_NR + i;
+		ida_gendisk[i].major_name = "ida";
+		ida_gendisk[i].minor_shift = NWD_SHIFT;
+		ida_gendisk[i].max_p = 16;
+		ida_gendisk[i].max_nr = 16;
+		ida_gendisk[i].init = ida_geninit;
+		ida_gendisk[i].part = ida + (i*256);
+		ida_gendisk[i].sizes = ida_sizes + (i*256);
+		/* ida_gendisk[i].nr_real is handled by getgeometry */
+	
+		blk_dev[MAJOR_NR+i].request_fn = request_fns[i];
+		blksize_size[MAJOR_NR+i] = ida_blocksizes + (i*256);
+		hardsect_size[MAJOR_NR+i] = ida_hardsizes + (i*256);
+		read_ahead[MAJOR_NR+i] = READ_AHEAD;
+		max_sectors[MAJOR_NR+i] = ida_maxsectors + (i*256);
+		max_segments[MAJOR_NR+i] = ida_maxsegments + (i*256);
+
+		/* Get on the disk list */
+		ida_gendisk[i].next = gendisk_head;
+		gendisk_head = &ida_gendisk[i];
+
+		init_timer(&hba[i]->timer);
+		hba[i]->timer.expires = jiffies + IDA_TIMER;
+		hba[i]->timer.data = (unsigned long)hba[i];
+		hba[i]->timer.function = ida_timer;
+		add_timer(&hba[i]->timer);
+
+	}
+	/* done ! */
+}
+
+/*
+ * Find the controller and initialize it
+ */
+static int cpqarray_pci_detect(void)
+{
+	int index;
+	unchar bus=0, dev_fn=0;
+	
+	for(index=0; ; index++) {
+		if (pcibios_find_device(PCI_VENDOR_ID_COMPAQ,
+			PCI_DEVICE_ID_COMPAQ_SMART2P, index, &bus, &dev_fn))
+			break;
+
+		if (index == 1000000) break;
+		
+		hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
+		memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
+		cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn);
+		sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
+		hba[nr_ctlr]->ctlr = nr_ctlr;
+		nr_ctlr++;
+	}
+
+	return nr_ctlr;
+}
+
+/*
+ * Find the IO address of the controller, its IRQ and so forth.  Fill
+ * in some basic stuff into the ctlr_info_t structure.
+ */
+static void cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn)
+{
+	ushort vendor_id, device_id, command;
+	unchar cache_line_size, latency_timer;
+	unchar irq, revision;
+	uint addr[6];
+
+	int i;
+
+	(void) pcibios_read_config_word(bus, device_fn,
+					PCI_VENDOR_ID, &vendor_id);
+	(void) pcibios_read_config_word(bus, device_fn,
+					PCI_DEVICE_ID, &device_id);
+	(void) pcibios_read_config_word(bus, device_fn,
+					PCI_COMMAND, &command);
+	for(i=0; i<6; i++)
+		(void) pcibios_read_config_dword(bus, device_fn,
+				PCI_BASE_ADDRESS_0 + i*4, addr+i);
+
+	(void) pcibios_read_config_byte(bus, device_fn,
+					PCI_CLASS_REVISION,&revision);
+	(void) pcibios_read_config_byte(bus, device_fn,
+					PCI_INTERRUPT_LINE, &irq);
+	(void) pcibios_read_config_byte(bus, device_fn,
+					PCI_CACHE_LINE_SIZE, &cache_line_size);
+	(void) pcibios_read_config_byte(bus, device_fn,
+					PCI_LATENCY_TIMER, &latency_timer);
+
+DBGINFO(
+	printk("vendor_id = %x\n", vendor_id);
+	printk("device_id = %x\n", device_id);
+	printk("command = %x\n", command);
+	for(i=0; i<6; i++)
+		printk("addr[%d] = %x\n", i, addr[i]);
+	printk("revision = %x\n", revision);
+	printk("irq = %x\n", irq);
+	printk("cache_line_size = %x\n", cache_line_size);
+	printk("latency_timer = %x\n", latency_timer);
+);
+
+	c->intr = irq;
+	c->ioaddr = addr[0] & ~0x1;
+
+	/*
+	 * Memory base addr is first addr with the first bit _not_ set
+	 */
+	for(i=0; i<6; i++)
+		if (!(addr[i] & 0x1)) {
+			c->paddr = addr[i];
+			break;
+		}
+	c->vaddr = remap_pci_mem(c->paddr, 128);
+}
+
+/*
+ * Map (physical) PCI mem into (virtual) kernel space
+ */
+static ulong remap_pci_mem(ulong base, ulong size)
+{
+        ulong page_base        = ((ulong) base) & PAGE_MASK;
+        ulong page_offs        = ((ulong) base) - page_base;
+        ulong page_remapped    = (ulong) vremap(page_base, page_offs+size);
+
+        return (ulong) (page_remapped ? (page_remapped + page_offs) : 0UL);
+}
+
+/*
+ * Open.  Make sure the device is really there.
+ */
+static int ida_open(struct inode *inode, struct file *filep)
+{
+	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
+	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
+
+	DBGINFO(printk("ida_open %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) );
+	if (ctlr > MAX_CTLR || hba[ctlr] == NULL)
+		return -ENXIO;
+
+	if (!suser() && ida_sizes[(ctlr << CTLR_SHIFT) +
+						MINOR(inode->i_rdev)] == 0)
+		return -ENXIO;
+
+	/*
+	 * Root is allowed to open raw volume zero even if its not configured
+	 * so array config can still work.  I don't think I really like this,
+	 * but I'm already using way to many device nodes to claim another one
+	 * for "raw controller".
+	 */
+	if (suser()
+		&& ida_sizes[(ctlr << CTLR_SHIFT) + MINOR(inode->i_rdev)] == 0 
+		&& MINOR(inode->i_rdev) != 0)
+		return -ENXIO;
+
+	hba[ctlr]->drv[dsk].usage_count++;
+	hba[ctlr]->usage_count++;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * Close.  Sync first.
+ */
+void ida_release(struct inode *inode, struct file *filep)
+{
+	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
+	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
+
+	DBGINFO(printk("ida_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) );
+	fsync_dev(inode->i_rdev);
+
+	hba[ctlr]->drv[dsk].usage_count--;
+	hba[ctlr]->usage_count--;
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * Enqueuing and dequeuing functions for cmdlists.
+ */
+static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c)
+{
+	if (*Qptr == NULL) {
+		*Qptr = c;
+		c->next = c->prev = c;
+	} else {
+		c->prev = (*Qptr)->prev;
+		c->next = (*Qptr);
+		(*Qptr)->prev->next = c;
+		(*Qptr)->prev = c;
+	}
+}
+
+static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c)
+{
+	if (c && c->next != c) {
+		if (*Qptr == c) *Qptr = c->next;
+		c->prev->next = c->next;
+		c->next->prev = c->prev;
+	} else {
+		*Qptr = NULL;
+	}
+	return c;
+}
+
+/*
+ * Get a request and submit it to the controller.
+ * This routine needs to grab all the requests it possibly can from the
+ * req Q and submit them.  Interrupts are off (and need to be off) when you
+ * are in here (either via the dummy do_ida_request functions or by being
+ * called from the interrupt handler
+ */
+void do_ida_request(int ctlr)
+{
+	ctlr_info_t *h = hba[ctlr];
+	cmdlist_t *c;
+	int seg;
+	char *lastdataend;
+	struct buffer_head *bh;
+	struct request *creq;
+
+	creq = blk_dev[MAJOR_NR+ctlr].current_request;
+	if (creq == NULL || creq->rq_status == RQ_INACTIVE)
+		goto doreq_done;
+
+	if (ctlr != MAJOR(creq->rq_dev)-MAJOR_NR ||
+		ctlr > nr_ctlr || h == NULL) {
+		printk("doreq cmd for %d, %x at %p\n",
+				ctlr, creq->rq_dev, creq);
+		complete_buffers(creq->bh, 0);
+		goto doreq_done;
+	}
+
+	if (h->Qdepth >= h->maxQ)
+		goto doreq_done;
+
+	if ((c = cmd_alloc(1)) == NULL)
+		goto doreq_done;
+
+	blk_dev[MAJOR_NR+ctlr].current_request = creq->next;
+	creq->rq_status = RQ_INACTIVE;
+	wake_up(&wait_for_request);
+
+	bh = creq->bh;
+
+	c->ctlr = ctlr;
+	c->hdr.unit = MINOR(creq->rq_dev) >> NWD_SHIFT;
+	c->hdr.prio = 0;
+	c->hdr.size = sizeof(rblk_t) >> 2;
+	c->size += sizeof(rblk_t);
+
+	c->req.hdr.next = 0;
+	c->req.hdr.rcode = 0;
+	c->req.bp = 0;
+	c->req.hdr.sg_cnt = creq->nr_segments;
+	c->req.hdr.reserved = 0;
+	c->req.hdr.blk = ida[(ctlr<<CTLR_SHIFT) + MINOR(creq->rq_dev)].start_sect + creq->sector;
+	c->req.hdr.blk_cnt = creq->nr_sectors;
+	c->bh = bh;
+	
+	seg = 0; lastdataend = NULL;
+	while(bh) {
+		if (bh->b_data == lastdataend) {
+			c->req.sg[seg-1].size += bh->b_size;
+			lastdataend += bh->b_size;
+		} else {
+			c->req.sg[seg].size = bh->b_size;
+			c->req.sg[seg].addr = (__u32) virt_to_bus(bh->b_data);
+			lastdataend = bh->b_data + bh->b_size;
+			if (seg++ > SG_MAX)
+				panic("SG list overflow\n");
+		}
+		bh = bh->b_reqnext;
+	}
+	if (seg != creq->nr_segments)
+		panic("seg != nr_segments\n");
+
+	c->req.hdr.cmd = (creq->cmd == READ) ? IDA_READ : IDA_WRITE;
+	c->type = CMD_RWREQ;
+#ifdef PROFILE_REQUESTS
+	c->start_time = rdtsc();
+#endif /* PROFILE_REQUESTS */
+
+	/* Put the request on the tail of the request queue */
+	addQ(&h->reqQ, c);
+	h->Qdepth++;
+	if (h->Qdepth > h->maxQsinceinit) h->maxQsinceinit = h->Qdepth;
+
+doreq_done:
+	start_io(h);
+}
+
+/* 
+ * start_io submits everything on a controller's request queue
+ * and moves it to the completion queue.
+ *
+ * Interrupts had better be off if you're in here
+ */
+static void start_io(ctlr_info_t *h)
+{
+	cmdlist_t *c;
+
+	while((c = h->reqQ) != NULL) {
+		/* Can't do anything if we're busy */
+		if (readl(h->vaddr + COMMAND_FIFO) == 0)
+			return;
+
+		/* Get the first entry from the request Q */
+		removeQ(&h->reqQ, c);
+		h->Qdepth--;
+	
+		/* Tell the controller to do our bidding */
+		writel(c->busaddr, h->vaddr + COMMAND_FIFO);
+
+		/* Get onto the completion Q */
+		addQ(&h->cmpQ, c);
+	}
+}
+
+
+static inline void complete_buffers(struct buffer_head *bh, int ok)
+{
+	struct buffer_head *xbh;
+	while(bh) {
+		xbh = bh->b_reqnext;
+		bh->b_reqnext = NULL;
+		mark_buffer_uptodate(bh, ok);
+		unlock_buffer(bh);
+		bh = xbh;
+	}
+}
+
+/*
+ * Mark all buffers that cmd was responsible for
+ */
+static inline void complete_command(cmdlist_t *cmd, int timeout)
+{
+	char buf[80];
+	int ok=1;
+
+	if (cmd->req.hdr.rcode & RCODE_NONFATAL &&
+		(hba[cmd->ctlr]->misc_tflags & MISC_NONFATAL_WARN) == 0) {
+			sprintf(buf, "Non Fatal error on ida/c%dd%d\n",
+					cmd->ctlr, cmd->hdr.unit);
+			console_print(buf);
+			hba[cmd->ctlr]->misc_tflags |= MISC_NONFATAL_WARN;
+	}
+	if (cmd->req.hdr.rcode & RCODE_FATAL) {
+		sprintf(buf, "Fatal error on ida/c%dd%d\n",
+				cmd->ctlr, cmd->hdr.unit);
+		console_print(buf);
+		ok = 0;
+	}
+	if (cmd->req.hdr.rcode & RCODE_INVREQ) {
+sprintf(buf, "Invalid request on ida/c%dd%d = (cmd=%x sect=%d cnt=%d sg=%d ret=%x)\n",
+				cmd->ctlr, cmd->hdr.unit, cmd->req.hdr.cmd,
+				cmd->req.hdr.blk, cmd->req.hdr.blk_cnt,
+				cmd->req.hdr.sg_cnt, cmd->req.hdr.rcode);
+		console_print(buf);
+		ok = 0;	
+	}
+	if (timeout) {
+		sprintf(buf, "Request timeout on ida/c%dd%d\n",
+				cmd->ctlr, cmd->hdr.unit);
+		console_print(buf);
+		ok = 0;
+	}
+	complete_buffers(cmd->bh, ok);
+}
+
+/*
+ *  The controller will interrupt us upon completion of commands.
+ *  Find the command on the completion queue, remove it, tell the OS and
+ *  try to queue up more IO
+ */
+void do_ida_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	ctlr_info_t *h = dev_id;
+	cmdlist_t *c;
+	unsigned long istat;
+	__u32 a,a1;
+
+	istat = readl(h->vaddr + INTR_PENDING);
+	/* Is this interrupt for us? */
+	if (istat == 0)
+		return;
+
+	/*
+	 * If there are completed commands in the completion queue,
+	 * we had better do something about it.
+	 */
+	if (istat & FIFO_NOT_EMPTY) {
+		while((a = readl(h->vaddr + COMMAND_COMPLETE_FIFO))) {
+			a1 = a; a &= ~3;
+			if ((c = h->cmpQ) == NULL) goto bad_completion;
+			while(c->busaddr != a) {
+				c = c->next;
+				if (c == h->cmpQ) break;
+			}
+			/*
+			 * If we've found the command, take it off the
+			 * completion Q and free it
+			 */
+			if (c->busaddr == a) {
+				removeQ(&h->cmpQ, c);
+				if (c->type == CMD_RWREQ) {
+#ifdef PROFILE_REQUESTS
+	unsigned int finish = (rdtsc() - c->start_time);
+	if (finish < h->min_latency) h->min_latency = finish;
+	if (finish > h->max_latency) h->max_latency = finish;
+	h->avg_latency = (h->avg_latency*h->nr_requests + finish) /
+				++h->nr_requests;
+#endif /* PROFILE_REQUESTS */
+					complete_command(c, 0);
+					cmd_free(c);
+				} else if (c->type == CMD_IOCTL_PEND) {
+					c->type = CMD_IOCTL_DONE;
+				}
+				continue;
+			}
+bad_completion:
+			printk("Completion of %08lx ignored\n", (unsigned long)a1);
+		}
+	}
+
+	/*
+	 * See if we can queue up some more IO (Is this safe?)
+	 */
+	do_ida_request(h->ctlr);
+}
+
+/*
+ * This timer is for timing out requests that haven't happened after
+ * IDA_TIMEOUT, or rather it _WAS_ for timing out "dead" requests.
+ * That didn't work quite like I expected and would cause crashes
+ * and other nonsense.
+ */
+static void ida_timer(unsigned long tdata)
+{
+	ctlr_info_t *h = (ctlr_info_t*)tdata;
+
+	h->timer.expires = jiffies + IDA_TIMER;
+	add_timer(&h->timer);
+	h->misc_tflags = 0;
+}
+
+/*
+ *  ida_ioctl does some miscellaneous stuff like reporting drive geometry,
+ *  setting readahead and submitting commands from userspace to the controller.
+ */
+int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg)
+{
+	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
+	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
+	int error;
+	int diskinfo[4];
+	struct hd_geometry *geo = (struct hd_geometry *)arg;
+	ida_ioctl_t *io = (ida_ioctl_t*)arg;
+	ida_ioctl_t my_io;
+
+	DBGINFO(printk("ida_ioctl %x %x %x\n", inode->i_rdev, cmd, arg));
+	switch(cmd) {
+	case HDIO_GETGEO:
+		error = verify_area(VERIFY_WRITE, geo, sizeof(*geo));
+		if (error) return error;
+ 		if (hba[ctlr]->drv[dsk].cylinders) {
+ 			diskinfo[0] = hba[ctlr]->drv[dsk].heads;
+ 			diskinfo[1] = hba[ctlr]->drv[dsk].sectors;
+ 			diskinfo[2] = hba[ctlr]->drv[dsk].cylinders;
+ 		} else {
+ 			diskinfo[0] = 0xff;
+ 			diskinfo[1] = 0x3f;
+ 			diskinfo[2] = hba[ctlr]->drv[dsk].nr_blks / (0xff*0x3f);
+ 		}
+		put_user(diskinfo[0], &geo->heads);
+		put_user(diskinfo[1], &geo->sectors);
+		put_user(diskinfo[2], &geo->cylinders);
+		put_user(ida[MINOR(inode->i_rdev)].start_sect, &geo->start);
+		return 0;
+	case IDAGETDRVINFO:
+		error = verify_area(VERIFY_WRITE, io, sizeof(*io));
+		if (error) return error;
+		memcpy_tofs(&io->c.drv,&hba[ctlr]->drv[dsk],sizeof(drv_info_t));
+		return 0;
+	case BLKRASET:
+		if (!suser()) return -EACCES;
+		if (!(inode->i_rdev)) return -EINVAL;
+		if (arg>0xff) return -EINVAL;
+		read_ahead[MAJOR(inode->i_rdev)] = arg;
+		return 0;
+	case BLKRAGET:
+		if (!arg) return -EINVAL;
+		error=verify_area(VERIFY_WRITE, (int*)arg, sizeof(int));
+		if (error) return error;
+		put_user(read_ahead[MAJOR(inode->i_rdev)], (int*)arg);
+		return 0;
+	case BLKRRPART:
+		return revalidate_logvol(inode->i_rdev, 1);
+	case IDAPASSTHRU:
+		if (!suser()) return -EPERM;
+		error = verify_area(VERIFY_READ|VERIFY_WRITE, io, sizeof(*io));
+		if (error) return error;
+		memcpy_fromfs(&my_io, io, sizeof(my_io));
+		error = ida_ctlr_ioctl(ctlr, dsk, &my_io);
+		if (error) return error;
+		memcpy_tofs(io, &my_io, sizeof(my_io));
+		return 0;
+	case IDAGETCTLRSIG:
+		if (!arg) return -EINVAL;
+		error=verify_area(VERIFY_WRITE, (int*)arg, sizeof(int));
+		if (error) return error;
+		put_user(hba[ctlr]->ctlr_sig, (int*)arg);
+		return 0;
+	case IDAREVALIDATEVOLS:
+		return revalidate_allvol(inode->i_rdev);
+
+	RO_IOCTLS(inode->i_rdev, arg);
+
+	default:
+		return -EBADRQC;
+	}
+		
+}
+/*
+ * ida_ctlr_ioctl is for passing commands to the controller from userspace.
+ * The command block (io) has already been copied to kernel space for us,
+ * however, any elements in the sglist need to be copied to kernel space
+ * or copied back to userspace.
+ *
+ * Only root may perform a controller passthru command, however I'm not doing
+ * any serious sanity checking on the arguments.  Doing an IDA_WRITE_MEDIA and
+ * putting a 64M buffer in the sglist is probably a *bad* idea.
+ */
+int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io)
+{
+	ctlr_info_t *h = hba[ctlr];
+	cmdlist_t *c;
+	void *p = NULL;
+	unsigned long flags;
+	int error;
+
+	DBGINFO(printk("ida_ctlr_ioctl %d %x %p\n", ctlr, dsk, io));
+	if ((c = cmd_alloc(0)) == NULL)
+		return -ENOMEM;
+	c->ctlr = ctlr;
+	c->hdr.unit = (io->unit & UNITVALID) ? io->unit &0x7f : dsk;
+	c->hdr.prio = 0;
+	c->hdr.size = sizeof(rblk_t) >> 2;
+	c->size += sizeof(rblk_t);
+
+	c->req.hdr.next = 0;
+	c->req.hdr.rcode = 0;
+	c->req.bp = 0;
+	c->req.hdr.reserved = 0;
+
+	c->req.hdr.blk = 0;
+	c->req.hdr.blk_cnt = 0;
+	c->req.hdr.cmd = io->cmd;
+	c->type = CMD_IOCTL_PEND;
+
+	/* Pre submit processing */
+	switch(io->cmd) {
+	case PASSTHRU_A:
+		error = verify_area(VERIFY_READ|VERIFY_WRITE,
+				(void*)io->sg[0].addr, io->sg[0].size);
+		if (error) goto ioctl_err_exit;
+
+		p = kmalloc(io->sg[0].size, GFP_KERNEL);
+		if (!p) { error = -ENOMEM; goto ioctl_err_exit; }
+		memcpy_fromfs(p, (void*)io->sg[0].addr, io->sg[0].size);
+		c->req.bp = virt_to_bus(&(io->c));
+		c->req.sg[0].size = io->sg[0].size;
+		c->req.sg[0].addr = virt_to_bus(p);
+		c->req.hdr.sg_cnt = 1;
+		break;
+	case IDA_READ:
+		error = verify_area(VERIFY_WRITE,
+				(void*)io->sg[0].addr, io->sg[0].size);
+		if (error) goto ioctl_err_exit;
+		p = kmalloc(io->sg[0].size, GFP_KERNEL);
+		if (!p) { error = -ENOMEM; goto ioctl_err_exit; }
+		c->req.sg[0].size = io->sg[0].size;
+		c->req.sg[0].addr = virt_to_bus(p);
+		c->req.hdr.sg_cnt = 1;
+		break;
+	case IDA_WRITE:
+	case IDA_WRITE_MEDIA:
+		error = verify_area(VERIFY_READ,
+				(void*)io->sg[0].addr, io->sg[0].size);
+		if (error) goto ioctl_err_exit;
+		p = kmalloc(io->sg[0].size, GFP_KERNEL);
+		if (!p) { error = -ENOMEM; goto ioctl_err_exit; }
+		memcpy_fromfs(p, (void*)io->sg[0].addr, io->sg[0].size);
+		c->req.sg[0].size = io->sg[0].size;
+		c->req.sg[0].addr = virt_to_bus(p);
+		c->req.hdr.sg_cnt = 1;
+		break;
+	default:
+		c->req.sg[0].size = sizeof(io->c);
+		c->req.sg[0].addr = virt_to_bus(&io->c);
+		c->req.hdr.sg_cnt = 1;
+	}
+
+	/* Put the request on the tail of the request queue */
+	save_flags(flags);
+	cli();
+	addQ(&h->reqQ, c);
+	h->Qdepth++;
+	start_io(h);
+	restore_flags(flags);
+
+	/* Wait for completion */
+	while(c->type != CMD_IOCTL_DONE)
+		schedule();
+
+	/* Post submit processing */
+	switch(io->cmd) {
+	case PASSTHRU_A:
+	case IDA_READ:
+		memcpy_tofs((void*)io->sg[0].addr, p, io->sg[0].size);
+		/* fall through and free p */
+	case IDA_WRITE:
+	case IDA_WRITE_MEDIA:
+		kfree(p);
+		break;
+	default:
+		/* Nothing to do */
+	}
+
+	io->rcode = c->req.hdr.rcode;
+	error = 0;
+ioctl_err_exit:
+	cmd_free(c);
+	return error;
+}
+
+/*
+ * Sooner or later we'll want to maintain our own cache of
+ * commands.  For now, just use kmalloc to get them
+ */
+cmdlist_t * cmd_alloc(int intr)
+{
+	cmdlist_t * c;
+
+	c = kmalloc(sizeof(cmdlist_t), (intr) ? GFP_ATOMIC : GFP_KERNEL);
+	memset(c, 0, sizeof(cmdlist_t));
+	c->busaddr = virt_to_bus(c);
+#ifdef PROFILE_MEMUSAGE
+	nr_allocs++;
+#endif
+	return c;
+}
+
+void cmd_free(cmdlist_t *c)
+{
+#ifdef PROFILE_MEMUSAGE
+	nr_frees++;
+#endif
+	kfree(c);
+}
+
+/***********************************************************************
+    name:        sendcmd
+    Send a command to an IDA using the memory mapped FIFO interface
+    and wait for it to complete.  
+    This routine should only be called at init time.
+***********************************************************************/
+int sendcmd(
+	__u8	cmd,
+	int	ctlr,
+	void	*buff,
+	size_t	size,
+	unsigned int blk,
+	unsigned int blkcnt,
+	unsigned int log_unit )
+{
+	cmdlist_t *c;
+	int complete;
+	__u32 base_ptr;
+	unsigned long temp;
+	unsigned long i;
+	ctlr_info_t *info_p = hba[ctlr];
+
+	c = cmd_alloc(0);
+	c->ctlr = ctlr;
+	c->hdr.unit = log_unit;
+	c->hdr.prio = 0;
+	c->hdr.size = sizeof(rblk_t) >> 2;
+	c->size += sizeof(rblk_t);
+
+	/* The request information. */
+	c->req.hdr.next = 0;
+	c->req.hdr.rcode = 0;
+	c->req.bp = 0;
+	c->req.hdr.sg_cnt = 1;
+	c->req.hdr.reserved = 0;
+	
+	if (size == 0)
+		c->req.sg[0].size = 512;
+	else
+		c->req.sg[0].size = size;
+
+	c->req.hdr.blk = blk;
+	c->req.hdr.blk_cnt = blkcnt;
+	c->req.hdr.cmd = (unsigned char) cmd;
+	c->req.sg[0].addr = (__u32) virt_to_bus(buff);
+	flushcomplete(ctlr);
+	/*
+	 * Disable interrupt
+	 */
+	base_ptr = info_p->vaddr;
+	writel(0, base_ptr + INTR_MASK);
+	/* Make sure there is room in the command FIFO */
+	/* Actually it should be completely empty at this time. */
+	for (i = 200000; i > 0; i--) {
+		temp = readl(base_ptr + COMMAND_FIFO);
+		if (temp != 0) {
+			break;
+		}
+		udelay(10);
+DBG(
+		printk("ida%d: idaSendPciCmd FIFO full, waiting!\n",
+		       ctlr);
+);
+	}
+	/*
+	 * Send the cmd
+	 */
+	writel(c->busaddr, base_ptr + COMMAND_FIFO);
+	complete = pollcomplete(ctlr);
+	if (complete != 1) {
+		if (complete != c->busaddr) {
+			printk(
+			"ida%d: idaSendPciCmd "
+		      "Invalid command list address returned! (%08lx)\n",
+				ctlr, (unsigned long)complete);
+			cmd_free(c);
+			return (IO_ERROR);
+		}
+	} else {
+		printk(
+			"ida%d: idaSendPciCmd Timeout out, "
+			"No command list address returned!\n",
+			ctlr);
+		cmd_free(c);
+		return (IO_ERROR);
+	}
+
+	if (c->req.hdr.rcode & 0x00FE) {
+		if (!(c->req.hdr.rcode & BIG_PROBLEM)) {
+			printk(
+			"ida%d: idaSendPciCmd, error: Controller failed "
+				"at init time "
+				"cmd: 0x%x, return code = 0x%x\n",
+				ctlr, c->req.hdr.cmd, c->req.hdr.rcode);
+
+			cmd_free(c);
+			return (IO_ERROR);
+		}
+	}
+	cmd_free(c);
+	return (IO_OK);
+}
+
+int frevalidate_logvol(kdev_t dev)
+{
+	return revalidate_logvol(dev, 0);
+}
+
+/*
+ * revalidate_allvol is for online array config utilities.  After a
+ * utility reconfigures the drives in the array, it can use this function
+ * (through an ioctl) to make the driver zap any previous disk structs for
+ * that controller and get new ones.
+ *
+ * Right now I'm using the getgeometry() function to do this, but this
+ * function should probably be finer grained and allow you to revalidate one
+ * particualar logical volume (instead of all of them on a particular
+ * controller).
+ */
+static int revalidate_allvol(kdev_t dev)
+{
+	int ctlr, i;
+	unsigned long flags;
+
+	ctlr = MAJOR(dev) - MAJOR_NR;
+	if (MINOR(dev) != 0)
+		return -ENXIO;
+
+	save_flags(flags);
+	cli();
+	if (hba[ctlr]->usage_count > 1) {
+		restore_flags(flags);
+		printk("Device busy for volume revalidation (usage=%d)\n",
+					hba[ctlr]->usage_count);
+		return -EBUSY;
+	}
+
+	hba[ctlr]->usage_count++;
+	restore_flags(flags);
+
+	/*
+	 * Set the partition and block size structures for all volumes
+	 * on this controller to zero.  We will reread all of this data
+	 */
+	memset(ida+(ctlr*256),            0, sizeof(struct hd_struct)*NWD*16);
+	memset(ida_sizes+(ctlr*256),      0, sizeof(int)*NWD*16);
+	memset(ida_blocksizes+(ctlr*256), 0, sizeof(int)*NWD*16);
+	memset(ida_hardsizes+(ctlr*256),  0, sizeof(int)*NWD*16);
+	ida_gendisk[ctlr].nr_real = 0;
+
+	/*
+	 * Tell the array controller not to give us any interupts while
+	 * we check the new geometry.  Then turn interrupts back on when
+	 * we're done.
+	 */
+	writel(0, hba[ctlr]->vaddr + INTR_MASK);
+	getgeometry(ctlr);
+	writel(FIFO_NOT_EMPTY, hba[ctlr]->vaddr + INTR_MASK);
+
+	ida_geninit(&ida_gendisk[ctlr]);
+	for(i=0; i<NWD; i++)
+		if (ida_sizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)])
+			revalidate_logvol(dev+(i<<NWD_SHIFT), 2);
+
+	hba[ctlr]->usage_count--;
+	return 0;
+}
+
+/* Borrowed and adapted from sd.c */
+int revalidate_logvol(kdev_t dev, int maxusage)
+{
+	int ctlr, target;
+	struct gendisk *gdev;
+	unsigned long flags;
+	int max_p;
+	int start;
+	int i;
+
+	target = DEVICE_NR(dev);
+	ctlr = MAJOR(dev) - MAJOR_NR;
+	gdev = &ida_gendisk[ctlr];
+	
+	save_flags(flags);
+	cli();
+	if (hba[ctlr]->drv[target].usage_count > maxusage) {
+		restore_flags(flags);
+		printk("Device busy for revalidation (usage=%d)\n",
+					hba[ctlr]->drv[target].usage_count);
+		return -EBUSY;
+	}
+
+	hba[ctlr]->drv[target].usage_count++;
+	restore_flags(flags);
+
+	max_p = gdev->max_p;
+	start = target << gdev->minor_shift;
+
+	for(i=max_p; i>=0; i--) {
+		int minor = start+i;
+		kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor);
+		sync_dev(devi);
+		invalidate_inodes(devi);
+		invalidate_buffers(devi);
+		gdev->part[minor].start_sect = 0;	
+		gdev->part[minor].nr_sects = 0;	
+
+		/* reset the blocksize so we can read the partition table */
+		blksize_size[MAJOR_NR+ctlr][minor] = 1024;
+	}
+
+	gdev->part[start].nr_sects =  hba[ctlr]->drv[target].nr_blks;
+	resetup_one_dev(gdev, target);
+	hba[ctlr]->drv[target].usage_count--;
+	return 0;
+}
+
+
+/********************************************************************
+    name: pollcomplete
+    Wait polling for a command to complete.
+    The memory mapped FIFO is polled for the completion.
+    Used only at init time, interrupts disabled.
+ ********************************************************************/
+int pollcomplete(int ctlr)
+{
+	int done;
+	int i;
+	unsigned long base_ptr = hba[ctlr]->vaddr;
+
+	/* Wait (up to 2 seconds) for a command to complete */
+
+	for (i = 200000; i > 0; i--) {
+		done = readl(base_ptr + COMMAND_COMPLETE_FIFO);
+		if (done == 0) {
+			udelay(10);	/* a short fixed delay */
+		} else
+			return (done);
+	}
+	/* Invalid address to tell caller we ran out of time */
+	return 1;
+}
+
+/*
+ * Clear the complete FIFO
+
+ Polling routine.
+ This should only be used at init time.
+ Any commands unexpectedly found in the completed command fifo
+ will be discarded.  There should be none.
+ Called in only one place.
+ Note this reads and discards any completed commands but does not
+ wait for any uncompleted commands.
+ This is kinda goofy.
+
+ */
+void flushcomplete(int ctlr)
+{
+
+	unsigned long base_ptr = hba[ctlr]->vaddr;
+	unsigned long ret_addr;
+	unsigned int i;
+
+	for (i = 200000; i > 0; i--) {
+		ret_addr = readl(base_ptr + COMMAND_COMPLETE_FIFO);
+		if (ret_addr == 0) {
+			break;
+		}
+		udelay(10);
+DBG(
+		printk("ida%d: flushcomplete "
+		       "Discarding completion %x!\n",
+		       ctlr, (unsigned int)ret_addr);
+);
+	}
+}
+
+
+
+/*****************************************************************
+    idaGetGeometry
+    Get ida logical volume geometry from the controller 
+    This is a large bit of code which once existed in two flavors,
+    for EISA and PCI.  It is used only at init time.
+****************************************************************
+*/
+void getgeometry(int ctlr)
+{				
+	id_log_drv_t *id_ldrive;
+	id_ctlr_t *id_ctlr_buf;
+	sense_log_drv_stat_t *id_lstatus_buf;
+	config_t *sense_config_buf;
+	unsigned int log_unit, log_index;
+	int ret_code, size;
+	drv_info_t *drv;
+	ctlr_info_t *info_p = hba[ctlr];
+
+	id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
+	id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
+	id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
+	sense_config_buf = (config_t *)kmalloc(sizeof(config_t), GFP_KERNEL);
+
+	memset(id_ldrive, 0, sizeof(id_log_drv_t));
+	memset(id_ctlr_buf, 0, sizeof(id_ctlr_t));
+	memset(id_lstatus_buf, 0, sizeof(sense_log_drv_stat_t));
+	memset(sense_config_buf, 0, sizeof(config_t));
+
+	info_p->phys_drives = 0;
+	info_p->log_drv_map = 0;
+	info_p->drv_assign_map = 0;
+	info_p->drv_spare_map = 0;
+	info_p->mp_failed_drv_map = 0;	/* only initialized here */
+	/* Get controllers info for this logical drive */
+	ret_code = sendcmd(ID_CTLR, ctlr, id_ctlr_buf, 0, 0, 0, 0);
+	if (ret_code == IO_ERROR) {
+		/*
+		 * If can't get controller info, set the logical drive map to 0,
+		 * so the idastubopen will fail on all logical drives
+		 * on the controller.
+		 */
+		goto geo_ret;	/* release the buf and return */
+	}
+	info_p->log_drives = id_ctlr_buf->nr_drvs;;
+	info_p->firm_rev = id_ctlr_buf->firm_rev;
+	info_p->ctlr_sig = id_ctlr_buf->cfg_sig;
+	/*
+	 * Initialize logical drive map to zero
+	 */
+#ifdef REDUNDANT
+	info_p->log_drive_map = 0;
+#endif				/* #ifdef REDUNDANT */
+	log_index = 0;
+	/*
+	 * Get drive geometry for all logical drives
+	 */
+	for (log_unit = 0;
+	     (log_index < id_ctlr_buf->nr_drvs)
+	     && (log_unit < NWD);
+	     log_unit++) {
+
+		size = sizeof(sense_log_drv_stat_t);
+
+		/*
+		   Send "Identify logical drive status" cmd
+		 */
+		ret_code = sendcmd(SENSE_LOG_DRV_STAT,
+			     ctlr, id_lstatus_buf, size, 0, 0, log_unit);
+		if (ret_code == IO_ERROR) {
+			/*
+			   If can't get logical drive status, set
+			   the logical drive map to 0, so the
+			   idastubopen will fail for all logical drives
+			   on the controller. 
+			 */
+			info_p->log_drv_map = 0;	
+			printk(
+			     "ida%d: idaGetGeometry - Controller failed "
+				"to report status of logical drive %d\n"
+			 "Access to this controller has been disabled\n",
+				ctlr, log_unit);
+			goto geo_ret;	/* release the buf and return */
+
+		}
+		/*
+		   Make sure the logical drive is configured
+		 */
+		if (id_lstatus_buf->status != LOG_NOT_CONF) {
+			ret_code = sendcmd(ID_LOG_DRV, ctlr, id_ldrive,
+			       sizeof(id_log_drv_t), 0, 0, log_unit);
+			/*
+			   If error, the bit for this
+			   logical drive won't be set and
+			   idastubopen will return error. 
+			 */
+			if (ret_code != IO_ERROR) {
+				drv = &info_p->drv[log_unit];
+				drv->blk_size = id_ldrive->blk_size;
+				drv->nr_blks = id_ldrive->nr_blks;
+ 				drv->cylinders = id_ldrive->drv.cyl;
+ 				drv->heads = id_ldrive->drv.heads;
+ 				drv->sectors = id_ldrive->drv.sect_per_track;
+				info_p->log_drv_map |=	(1 << log_unit);
+
+				printk("ida/c%dd%d: blksz=%d nr_blks=%d\n",
+						ctlr, log_unit, drv->blk_size,
+						drv->nr_blks);
+				ret_code = sendcmd(SENSE_CONFIG,
+						  ctlr, sense_config_buf,
+				 sizeof(config_t), 0, 0, log_unit);
+				if (ret_code == IO_ERROR) {
+					info_p->log_drv_map = 0;
+					goto geo_ret;	/* release the buf and return */
+				}
+				info_p->phys_drives =
+				    sense_config_buf->ctlr_phys_drv;
+				info_p->drv_assign_map
+				    |= sense_config_buf->drv_asgn_map;
+				info_p->drv_assign_map
+				    |= sense_config_buf->spare_asgn_map;
+				info_p->drv_spare_map
+				    |= sense_config_buf->spare_asgn_map;
+			}	/* end of if no error on id_ldrive */
+			log_index = log_index + 1;
+		}		/* end of if logical drive configured */
+	}			/* end of for log_unit */
+      geo_ret:
+	kfree(id_ctlr_buf);
+	kfree(id_ldrive);
+	kfree(id_lstatus_buf);
+	kfree(sense_config_buf);
+}
diff -urN linux-2.0.37-pre3/drivers/block/cpqarray.h linux-2.0.37-pre4/drivers/block/cpqarray.h
--- linux-2.0.37-pre3/drivers/block/cpqarray.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.37-pre4/drivers/block/cpqarray.h	2003-08-15 15:04:28.000000000 -0700
@@ -0,0 +1,95 @@
+/*
+ *    Disk Array driver for Compaq SMART2 Controllers
+ *    Copyright 1998 Compaq Computer Corporation
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *    NON INFRINGEMENT.  See the GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ *    If you want to make changes, improve or add functionality to this
+ *    driver, you'll probably need the Compaq Array Controller Interface
+ *    Specificiation (Document number ECG086/1198)
+ */
+#ifndef CPQARRAY_H
+#define CPQARRAY_H
+
+#ifdef __KERNEL__
+#include <linux/blkdev.h>
+#include <linux/locks.h>
+#include <linux/malloc.h>
+#include <linux/config.h>
+#include <linux/md.h>
+#include <linux/timer.h>
+#endif
+
+#include "ida_cmd.h"
+
+#define IO_OK		0
+#define IO_ERROR	1
+#define NWD		16
+#define NWD_SHIFT	4
+
+#define IDA_TIMER	(5*HZ)
+#define IDA_TIMEOUT	(10*HZ)
+
+#define MISC_NONFATAL_WARN	0x01
+
+typedef struct {
+	unsigned blk_size;
+	unsigned nr_blks;
+	unsigned cylinders;
+	unsigned heads;
+	unsigned sectors;
+	int usage_count;
+} drv_info_t;
+
+typedef struct {
+	int	ctlr;
+	char	devname[8];
+	__u32	log_drv_map;
+	__u32	drv_assign_map;
+	__u32	drv_spare_map;
+	__u32	mp_failed_drv_map;
+
+	int	firm_rev;
+	int	ctlr_sig;
+
+	int	log_drives;
+	int	phys_drives;
+
+	__u32	board_id;
+	__u32	vaddr;
+	__u32	paddr;
+	__u32	ioaddr;
+	int	intr;
+	int	usage_count;
+	drv_info_t	drv[NWD];
+	int	proc;
+
+	cmdlist_t *reqQ;
+	cmdlist_t *cmpQ;
+	unsigned int Qdepth;
+	unsigned int maxQ;
+	unsigned int maxQsinceinit;
+
+	unsigned int min_latency;
+	unsigned int avg_latency;
+	unsigned int max_latency;
+	unsigned int nr_requests;
+	struct timer_list timer;
+	unsigned int misc_tflags;
+} ctlr_info_t;
+
+#endif /* CPQARRAY_H */
diff -urN linux-2.0.37-pre3/drivers/block/DAC960.c linux-2.0.37-pre4/drivers/block/DAC960.c
--- linux-2.0.37-pre3/drivers/block/DAC960.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.37-pre4/drivers/block/DAC960.c	2003-08-15 15:04:28.000000000 -0700
@@ -0,0 +1,1979 @@
+/*
+
+  Linux Driver for Mylex DAC960 PCI RAID Controllers
+
+  Copyright 1998 by Leonard N. Zubkoff <lnz@dandelion.com>
+
+  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.
+
+  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.
+
+*/
+
+
+#define DAC960_DriverVersion		"2.0.0 Beta3"
+#define DAC960_DriverDate		"29 November 1998"
+
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ioport.h>
+#include <linux/locks.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include "DAC960.h"
+
+
+/*
+  DAC960_ControllerCount is the number of DAC960 Controllers.
+*/
+
+static int
+  DAC960_ControllerCount =			0;
+
+
+/*
+  DAC960_Controllers is an array of pointers to the DAC960 Controller
+  structures.
+*/
+
+static DAC960_Controller_T
+  *DAC960_Controllers[DAC960_MaxControllers] =	{ NULL };
+
+
+/*
+  DAC960_FileOperations is the File Operations structure for DAC960 Logical
+  Disk Devices.
+*/
+
+static FileOperations_T
+  DAC960_FileOperations =
+    { lseek:		    NULL,
+      read:		    block_read,
+      write:		    block_write,
+      readdir:		    NULL,
+      select:		    NULL,
+      ioctl:		    DAC960_Ioctl,
+      mmap:		    NULL,
+      open:		    DAC960_Open,
+      release:		    DAC960_Release,
+      fsync:		    block_fsync,
+      fasync:		    NULL,
+      check_media_change:   NULL,
+      revalidate:	    NULL };
+
+
+/*
+  DAC960_AnnounceDriver announces the Driver Version and Date, Author's Name,
+  Copyright Notice, and Electronic Mail Address.
+*/
+
+static void DAC960_AnnounceDriver(DAC960_Controller_T *Controller)
+{
+  DAC960_Announce("***** DAC960 RAID Driver Version "
+		  DAC960_DriverVersion " of "
+		  DAC960_DriverDate " *****\n", Controller);
+  DAC960_Announce("Copyright 1998 by Leonard N. Zubkoff "
+		  "<lnz@dandelion.com>\n", Controller);
+}
+
+
+/*
+  DAC960_Failure prints a standardized error message, and then returns false.
+*/
+
+static boolean DAC960_Failure(DAC960_Controller_T *Controller,
+			      char *ErrorMessage)
+{
+  DAC960_Error("While configuring DAC960 PCI RAID Controller at\n",
+	       Controller);
+  if (Controller->IO_Address == 0)
+    DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A "
+		 "PCI Address 0x%X\n", Controller,
+		 Controller->Bus, Controller->Device,
+		 Controller->Function, Controller->PCI_Address);
+  else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address "
+		    "0x%X PCI Address 0x%X\n", Controller,
+		    Controller->Bus, Controller->Device,
+		    Controller->Function, Controller->IO_Address,
+		    Controller->PCI_Address);
+  DAC960_Error("%s FAILED - DETACHING\n", Controller, ErrorMessage);
+  return false;
+}
+
+
+/*
+  DAC960_ClearCommand clears critical fields of Command.
+*/
+
+static inline void DAC960_ClearCommand(DAC960_Command_T *Command)
+{
+  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+  CommandMailbox->Words[0] = 0;
+  CommandMailbox->Words[1] = 0;
+  CommandMailbox->Words[2] = 0;
+  CommandMailbox->Words[3] = 0;
+  Command->CommandStatus = 0;
+}
+
+
+/*
+  DAC960_AllocateCommand allocates a Command structure from Controller's
+  free list.
+*/
+
+static inline DAC960_Command_T *DAC960_AllocateCommand(DAC960_Controller_T
+						       *Controller)
+{
+  DAC960_Command_T *Command = Controller->FreeCommands;
+  if (Command == NULL) return NULL;
+  Controller->FreeCommands = Command->Next;
+  Command->Next = NULL;
+  return Command;
+}
+
+
+/*
+  DAC960_DeallocateCommand deallocates Command, returning it to Controller's
+  free list.
+*/
+
+static inline void DAC960_DeallocateCommand(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  Command->Next = Controller->FreeCommands;
+  Controller->FreeCommands = Command;
+}
+
+
+/*
+  DAC960_QueueCommand queues Command.
+*/
+
+static void DAC960_QueueCommand(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V4_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+  DAC960_V4_CommandMailbox_T *NextCommandMailbox;
+  CommandMailbox->Common.CommandIdentifier = Command - Controller->Commands;
+  switch (Controller->ControllerType)
+    {
+    case DAC960_V4_Controller:
+      NextCommandMailbox = Controller->NextCommandMailbox;
+      DAC960_V4_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+      if (Controller->PreviousCommandMailbox->Words[0] == 0)
+	DAC960_V4_NewCommand(ControllerBaseAddress);
+      Controller->PreviousCommandMailbox = NextCommandMailbox;
+      if (++NextCommandMailbox > Controller->LastCommandMailbox)
+	NextCommandMailbox = Controller->FirstCommandMailbox;
+      Controller->NextCommandMailbox = NextCommandMailbox;
+      break;
+    case DAC960_V3_Controller:
+      while (DAC960_V3_MailboxFullP(ControllerBaseAddress))
+	udelay(1);
+      DAC960_V3_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox);
+      DAC960_V3_NewCommand(ControllerBaseAddress);
+      break;
+    }
+}
+
+
+/*
+  DAC960_ExecuteCommand executes Command and waits for completion.  It
+  returns true on success and false on failure.
+*/
+
+static boolean DAC960_ExecuteCommand(DAC960_Command_T *Command)
+{
+  Semaphore_T Semaphore = MUTEX_LOCKED;
+  Command->Semaphore = &Semaphore;
+  DAC960_QueueCommand(Command);
+  down(&Semaphore);
+  return Command->CommandStatus == DAC960_NormalCompletion;
+}
+
+
+/*
+  DAC960_ExecuteType3 executes a DAC960 Type 3 Command and waits for
+  completion.  It returns true on success and false on failure.
+*/
+
+static boolean DAC960_ExecuteType3(DAC960_Controller_T *Controller,
+				   DAC960_CommandOpcode_T CommandOpcode,
+				   void *DataPointer)
+{
+  DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+  boolean Result;
+  DAC960_ClearCommand(Command);
+  Command->CommandType = DAC960_ImmediateCommand;
+  CommandMailbox->Type3.CommandOpcode = CommandOpcode;
+  CommandMailbox->Type3.BusAddress = Virtual_to_Bus(DataPointer);
+  Result = DAC960_ExecuteCommand(Command);
+  DAC960_DeallocateCommand(Command);
+  return Result;
+}
+
+
+/*
+  DAC960_ExecuteType3D executes a DAC960 Type 3D Command and waits for
+  completion.  It returns true on success and false on failure.
+*/
+
+static boolean DAC960_ExecuteType3D(DAC960_Controller_T *Controller,
+				    DAC960_CommandOpcode_T CommandOpcode,
+				    unsigned char Channel,
+				    unsigned char TargetID,
+				    void *DataPointer)
+{
+  DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+  boolean Result;
+  DAC960_ClearCommand(Command);
+  Command->CommandType = DAC960_ImmediateCommand;
+  CommandMailbox->Type3D.CommandOpcode = CommandOpcode;
+  CommandMailbox->Type3D.Channel = Channel;
+  CommandMailbox->Type3D.TargetID = TargetID;
+  CommandMailbox->Type3D.BusAddress = Virtual_to_Bus(DataPointer);
+  Result = DAC960_ExecuteCommand(Command);
+  DAC960_DeallocateCommand(Command);
+  return Result;
+}
+
+
+/*
+  DAC960_V4_EnableMemoryMailboxInterface enables the V4 Memory Mailbox
+  Interface.
+*/
+
+static boolean DAC960_V4_EnableMemoryMailboxInterface(DAC960_Controller_T
+						      *Controller)
+{
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V4_CommandMailbox_T *CommandMailboxesMemory;
+  DAC960_V4_StatusMailbox_T *StatusMailboxesMemory;
+  DAC960_CommandMailbox_T CommandMailbox;
+  DAC960_CommandStatus_T CommandStatus;
+  CommandMailboxesMemory =
+    (DAC960_V4_CommandMailbox_T *) __get_free_pages(GFP_KERNEL, 1, 0);
+  memset(CommandMailboxesMemory, 0, PAGE_SIZE << 1);
+  Controller->FirstCommandMailbox = CommandMailboxesMemory;
+  CommandMailboxesMemory += DAC960_CommandMailboxCount - 1;
+  Controller->LastCommandMailbox = CommandMailboxesMemory;
+  Controller->NextCommandMailbox = Controller->FirstCommandMailbox;
+  Controller->PreviousCommandMailbox = Controller->LastCommandMailbox;
+  StatusMailboxesMemory =
+    (DAC960_V4_StatusMailbox_T *) (CommandMailboxesMemory + 1);
+  Controller->FirstStatusMailbox = StatusMailboxesMemory;
+  StatusMailboxesMemory += DAC960_StatusMailboxCount - 1;
+  Controller->LastStatusMailbox = StatusMailboxesMemory;
+  Controller->NextStatusMailbox = Controller->FirstStatusMailbox;
+  /* Enable the Memory Mailbox Interface. */
+  CommandMailbox.TypeX.CommandOpcode = 0x2B;
+  CommandMailbox.TypeX.CommandIdentifier = 0;
+  CommandMailbox.TypeX.CommandOpcode2 = 0x10;
+  CommandMailbox.TypeX.CommandMailboxesBusAddress =
+    Virtual_to_Bus(Controller->FirstCommandMailbox);
+  CommandMailbox.TypeX.StatusMailboxesBusAddress =
+    Virtual_to_Bus(Controller->FirstStatusMailbox);
+  while (DAC960_V4_MailboxFullP(ControllerBaseAddress))
+    udelay(1);
+  DAC960_V4_WriteLegacyCommand(ControllerBaseAddress, &CommandMailbox);
+  DAC960_V4_NewCommand(ControllerBaseAddress);
+  while (!DAC960_V4_StatusAvailableP(ControllerBaseAddress))
+    udelay(1);
+  CommandStatus = DAC960_V4_ReadStatusRegister(ControllerBaseAddress);
+  DAC960_V4_AcknowledgeInterrupt(ControllerBaseAddress);
+  DAC960_V4_AcknowledgeStatus(ControllerBaseAddress);
+  return CommandStatus == DAC960_NormalCompletion;
+}
+
+
+/*
+  DAC960_DetectControllers detects DAC960 PCI RAID Controllers by interrogating
+  the PCI Configuration Space for DeviceID.
+*/
+
+static void DAC960_DetectControllers(unsigned short DeviceID)
+{
+  unsigned char Bus, DeviceFunction, IRQ_Channel;
+  unsigned int BaseAddress0, BaseAddress1;
+  unsigned int MemoryWindowSize = 0;
+  unsigned short Index = 0;
+  while (pcibios_find_device(PCI_VENDOR_ID_MYLEX, DeviceID,
+			     Index++, &Bus, &DeviceFunction) == 0)
+    {
+      DAC960_Controller_T *Controller = (DAC960_Controller_T *)
+	kmalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC);
+      DAC960_ControllerType_T ControllerType = 0;
+      DAC960_IO_Address_T IO_Address = 0;
+      DAC960_PCI_Address_T PCI_Address = 0;
+      unsigned char Device = DeviceFunction >> 3;
+      unsigned char Function = DeviceFunction & 0x7;
+      pcibios_read_config_dword(Bus, DeviceFunction,
+				PCI_BASE_ADDRESS_0, &BaseAddress0);
+      pcibios_read_config_dword(Bus, DeviceFunction,
+				PCI_BASE_ADDRESS_1, &BaseAddress1);
+      pcibios_read_config_byte(Bus, DeviceFunction,
+			       PCI_INTERRUPT_LINE, &IRQ_Channel);
+      switch (DeviceID)
+	{
+	case PCI_DEVICE_ID_MYLEX_DAC960P_V4:
+	  ControllerType = DAC960_V4_Controller;
+	  PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
+	  MemoryWindowSize = DAC960_V4_RegisterWindowSize;
+	  break;
+	case PCI_DEVICE_ID_MYLEX_DAC960P_V3:
+	  ControllerType = DAC960_V3_Controller;
+	  IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
+	  PCI_Address = BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
+	  MemoryWindowSize = DAC960_V3_RegisterWindowSize;
+	  break;
+	}
+      if (DAC960_ControllerCount == DAC960_MaxControllers)
+	{
+	  DAC960_Error("More than %d DAC960 Controllers detected - "
+		       "ignoring from Controller at\n",
+		       NULL, DAC960_MaxControllers);
+	  goto Failure;
+	}
+      if (Controller == NULL)
+	{
+	  DAC960_Error("Unable to allocate Controller structure for "
+		       "Controller at\n", NULL);
+	  goto Failure;
+	}
+      memset(Controller, 0, sizeof(DAC960_Controller_T));
+      Controller->ControllerNumber = DAC960_ControllerCount;
+      DAC960_Controllers[DAC960_ControllerCount++] = Controller;
+      if (IRQ_Channel == 0 || IRQ_Channel >= NR_IRQS)
+	{
+	  DAC960_Error("IRQ Channel %d illegal for Controller at\n",
+		       NULL, IRQ_Channel);
+	  goto Failure;
+	}
+      Controller->ControllerType = ControllerType;
+      Controller->IO_Address = IO_Address;
+      Controller->PCI_Address = PCI_Address;
+      Controller->Bus = Bus;
+      Controller->Device = Device;
+      Controller->Function = Function;
+      /*
+	Acquire shared access to the IRQ Channel.
+      */
+      strcpy(Controller->FullModelName, "DAC960");
+      if (request_irq(IRQ_Channel, DAC960_InterruptHandler,
+		      SA_INTERRUPT | SA_SHIRQ, Controller->FullModelName,
+		      Controller) < 0)
+	{
+	  DAC960_Error("Unable to acquire IRQ Channel %d for Controller at\n",
+		       NULL, IRQ_Channel);
+	  goto Failure;
+	}
+      Controller->IRQ_Channel = IRQ_Channel;
+      /*
+	Map the Controller Register Window.
+      */
+      if (MemoryWindowSize < PAGE_SIZE)
+	MemoryWindowSize = PAGE_SIZE;
+      Controller->MemoryMappedAddress =
+	ioremap_nocache(PCI_Address & PAGE_MASK, MemoryWindowSize);
+      Controller->BaseAddress =
+	Controller->MemoryMappedAddress + (PCI_Address & ~PAGE_MASK);
+      if (Controller->MemoryMappedAddress == NULL)
+	{
+	  DAC960_Error("Unable to map Controller Register Window for "
+		       "Controller at\n", NULL);
+	  goto Failure;
+	}
+      switch (DeviceID)
+	{
+	case PCI_DEVICE_ID_MYLEX_DAC960P_V4:
+	  DAC960_V4_DisableInterrupts(Controller->BaseAddress);
+	  if (!DAC960_V4_EnableMemoryMailboxInterface(Controller))
+	    {
+	      DAC960_Error("Unable to Enable V4 Memory Mailbox Interface "
+			   "for Controller at\n", NULL);
+	      goto Failure;
+	    }
+	  DAC960_V4_EnableInterrupts(Controller->BaseAddress);
+	  break;
+	case PCI_DEVICE_ID_MYLEX_DAC960P_V3:
+	  request_region(Controller->IO_Address, 0x80,
+			 Controller->FullModelName);
+	  DAC960_V3_EnableInterrupts(Controller->BaseAddress);
+	  break;
+	}
+      Controller->Commands[0].Controller = Controller;
+      Controller->Commands[0].Next = NULL;
+      Controller->FreeCommands = &Controller->Commands[0];
+      continue;
+    Failure:
+      if (IO_Address == 0)
+	DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A "
+		     "PCI Address 0x%X\n", NULL,
+		     Bus, Device, Function, PCI_Address);
+      else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address "
+			"0x%X PCI Address 0x%X\n", NULL,
+			Bus, Device, Function, IO_Address, PCI_Address);
+      if (Controller == NULL) break;
+      if (Controller->IRQ_Channel > 0)
+	free_irq(IRQ_Channel, Controller);
+      if (Controller->MemoryMappedAddress != NULL)
+	iounmap(Controller->MemoryMappedAddress);
+      kfree(Controller);
+      break;
+    }
+}
+
+
+/*
+  DAC960_ReadControllerConfiguration reads the Configuration Information
+  from Controller and initializes the Controller structure.
+*/
+
+static boolean DAC960_ReadControllerConfiguration(DAC960_Controller_T
+						  *Controller)
+{
+  DAC960_Enquiry2_T Enquiry2;
+  DAC960_Config2_T Config2;
+  int Channel, TargetID;
+  if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry,
+			   &Controller->Enquiry[0]))
+    return DAC960_Failure(Controller, "ENQUIRY");
+  if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry2, &Enquiry2))
+    return DAC960_Failure(Controller, "ENQUIRY2");
+  if (!DAC960_ExecuteType3(Controller, DAC960_ReadConfig2, &Config2))
+    return DAC960_Failure(Controller, "READ CONFIG2");
+  if (!DAC960_ExecuteType3(Controller, DAC960_GetLogicalDriveInformation,
+			   &Controller->LogicalDriveInformation[0]))
+    return DAC960_Failure(Controller, "GET LOGICAL DRIVE INFORMATION");
+  for (Channel = 0; Channel < Enquiry2.ActualChannels; Channel++)
+    for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++)
+      if (!DAC960_ExecuteType3D(Controller, DAC960_GetDeviceState,
+				Channel, TargetID,
+				&Controller->DeviceState[0][Channel][TargetID]))
+	  return DAC960_Failure(Controller, "GET DEVICE STATE");
+  /*
+    Initialize the Controller Model Name and Full Model Name fields.
+  */
+  switch (Enquiry2.HardwareID.SubModel)
+    {
+    case DAC960_P_PD_PU:
+      if (Enquiry2.SCSICapability.BusSpeed == DAC960_Ultra)
+	strcpy(Controller->ModelName, "DAC960PU");
+      else strcpy(Controller->ModelName, "DAC960PD");
+      break;
+    case DAC960_PL:
+      strcpy(Controller->ModelName, "DAC960PL");
+      break;
+    case DAC960_PG:
+      strcpy(Controller->ModelName, "DAC960PG");
+      break;
+    case DAC960_PJ:
+      strcpy(Controller->ModelName, "DAC960PJ");
+      break;
+    case DAC960_PTL_0:
+      strcpy(Controller->ModelName, "DAC960PTL-0");
+      break;
+    case DAC960_PTL_1:
+      strcpy(Controller->ModelName, "DAC960PTL-1");
+      break;
+    default:
+      return DAC960_Failure(Controller, "MODEL VERIFICATION");
+    }
+  strcpy(Controller->FullModelName, "Mylex ");
+  strcat(Controller->FullModelName, Controller->ModelName);
+  /*
+    Initialize the Controller Firmware Version field and verify that it
+    is a supported firmware version.  The supported firmware versions are:
+
+    DAC960PTL/PJ/PG	4.06 and above
+    DAC960PU/PD/PL	3.51 and above
+  */
+  sprintf(Controller->FirmwareVersion, "%d.%02d-%c-%02d",
+	  Enquiry2.FirmwareID.MajorVersion, Enquiry2.FirmwareID.MinorVersion,
+	  Enquiry2.FirmwareID.FirmwareType, Enquiry2.FirmwareID.TurnID);
+  if (!((Controller->FirmwareVersion[0] == '4' &&
+	 strcmp(Controller->FirmwareVersion, "4.06") >= 0) ||
+	(Controller->FirmwareVersion[0] == '3' &&
+	 strcmp(Controller->FirmwareVersion, "3.51") >= 0)))
+    {
+      DAC960_Failure(Controller, "FIRMWARE VERSION VERIFICATION");
+      DAC960_Error("Firmware Version = '%s'\n", Controller,
+		   Controller->FirmwareVersion);
+      return false;
+    }
+  /*
+    Initialize the Controller Channels, Memory Size, and SAF-TE Fault
+    Management Enabled fields.
+  */
+  Controller->Channels = Enquiry2.ActualChannels;
+  Controller->MemorySize = Enquiry2.MemorySize >> 20;
+  Controller->SAFTE_FaultManagementEnabled =
+    Enquiry2.FaultManagementType == DAC960_SAFTE;
+  /*
+    Initialize the Controller Queue Depth, Driver Queue Depth, Logical Drive
+    Count, Maximum Blocks per Command, and Maximum Scatter/Gather Segments.
+    The Driver Queue Depth must be at most one less than the Controller Queue
+    Depth to allow for an automatic drive rebuild operation.
+  */
+  Controller->ControllerQueueDepth = Controller->Enquiry[0].MaxCommands;
+  Controller->DriverQueueDepth = Controller->ControllerQueueDepth - 1;
+  Controller->LogicalDriveCount = Controller->Enquiry[0].NumberOfLogicalDrives;
+  Controller->MaxBlocksPerCommand = Enquiry2.MaxBlocksPerCommand;
+  Controller->MaxScatterGatherSegments = Enquiry2.MaxScatterGatherEntries;
+  /*
+    Initialize the Stripe Size, Segment Size, and Geometry Translation.
+  */
+  Controller->StripeSize = Config2.BlocksPerStripe * Config2.BlockFactor
+			   >> (10 - DAC960_BlockSizeBits);
+  Controller->SegmentSize = Config2.BlocksPerCacheLine * Config2.BlockFactor
+			    >> (10 - DAC960_BlockSizeBits);
+  switch (Config2.DriveGeometry)
+    {
+    case DAC960_Geometry_128_32:
+      Controller->GeometryTranslationHeads = 128;
+      Controller->GeometryTranslationSectors = 32;
+      break;
+    case DAC960_Geometry_255_63:
+      Controller->GeometryTranslationHeads = 255;
+      Controller->GeometryTranslationSectors = 63;
+      break;
+    default:
+      return DAC960_Failure(Controller, "CONFIG2 DRIVE GEOMETRY");
+    }
+  return true;
+}
+
+
+/*
+  DAC960_ReportControllerConfiguration reports the configuration of
+  Controller.
+*/
+
+static boolean DAC960_ReportControllerConfiguration(DAC960_Controller_T
+						    *Controller)
+{
+  int LogicalDriveNumber, Channel, TargetID;
+  DAC960_Info("Configuring Mylex %s PCI RAID Controller\n",
+	      Controller, Controller->ModelName);
+  DAC960_Info("  Firmware Version: %s, Channels: %d, Memory Size: %dMB\n",
+	      Controller, Controller->FirmwareVersion,
+	      Controller->Channels, Controller->MemorySize);
+  DAC960_Info("  PCI Bus: %d, Device: %d, Function: %d, I/O Address: ",
+	      Controller, Controller->Bus,
+	      Controller->Device, Controller->Function);
+  if (Controller->IO_Address == 0)
+    DAC960_Info("Unassigned\n", Controller);
+  else DAC960_Info("0x%X\n", Controller, Controller->IO_Address);
+  DAC960_Info("  PCI Address: 0x%X mapped at 0x%lX, IRQ Channel: %d\n",
+	      Controller, Controller->PCI_Address,
+	      (unsigned long) Controller->BaseAddress,
+	      Controller->IRQ_Channel);
+  DAC960_Info("  Controller Queue Depth: %d, "
+	      "Maximum Blocks per Command: %d\n",
+	      Controller, Controller->ControllerQueueDepth,
+	      Controller->MaxBlocksPerCommand);
+  DAC960_Info("  Driver Queue Depth: %d, "
+	      "Maximum Scatter/Gather Segments: %d\n",
+	      Controller, Controller->DriverQueueDepth,
+	      Controller->MaxScatterGatherSegments);
+  DAC960_Info("  Stripe Size: %dKB, Segment Size: %dKB, "
+	      "BIOS Geometry: %d/%d\n", Controller,
+	      Controller->StripeSize,
+	      Controller->SegmentSize,
+	      Controller->GeometryTranslationHeads,
+	      Controller->GeometryTranslationSectors);
+  if (Controller->SAFTE_FaultManagementEnabled)
+    DAC960_Info("  SAF-TE Fault Management Enabled\n", Controller);
+  DAC960_Info("  Physical Devices:\n", Controller);
+  for (Channel = 0; Channel < Controller->Channels; Channel++)
+    for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++)
+      {
+	DAC960_DeviceState_T *DeviceState =
+	  &Controller->DeviceState[0][Channel][TargetID];
+	if (!DeviceState->Present) continue;
+	switch (DeviceState->DeviceType)
+	  {
+	  case DAC960_OtherType:
+	    DAC960_Info("    %d:%d - Other\n", Controller, Channel, TargetID);
+	    break;
+	  case DAC960_DiskType:
+	    DAC960_Info("    %d:%d - Disk: %s, %d blocks\n", Controller,
+			Channel, TargetID,
+			(DeviceState->DeviceState == DAC960_Device_Dead
+			 ? "Dead"
+			 : DeviceState->DeviceState == DAC960_Device_WriteOnly
+			   ? "Write-Only"
+			   : DeviceState->DeviceState == DAC960_Device_Online
+			     ? "Online" : "Standby"),
+			DeviceState->DiskSize);
+	    break;
+	  case DAC960_SequentialType:
+	    DAC960_Info("    %d:%d - Sequential\n", Controller,
+			Channel, TargetID);
+	    break;
+	  case DAC960_CDROM_or_WORM_Type:
+	    DAC960_Info("    %d:%d - CD-ROM or WORM\n", Controller,
+			Channel, TargetID);
+	    break;
+	  }
+
+      }
+  DAC960_Info("  Logical Drives:\n", Controller);
+  for (LogicalDriveNumber = 0;
+       LogicalDriveNumber < Controller->LogicalDriveCount;
+       LogicalDriveNumber++)
+    {
+      DAC960_LogicalDriveInformation_T *LogicalDriveInformation =
+	&Controller->LogicalDriveInformation[0][LogicalDriveNumber];
+      DAC960_Info("    /dev/rd/c%dd%d: RAID-%d, %s, %d blocks, %s\n",
+		  Controller, Controller->ControllerNumber, LogicalDriveNumber,
+		  LogicalDriveInformation->RAIDLevel,
+		  (LogicalDriveInformation->LogicalDriveState ==
+		     DAC960_LogicalDrive_Online
+		   ? "Online"
+		   : LogicalDriveInformation->LogicalDriveState ==
+		     DAC960_LogicalDrive_Critical
+		     ? "Critical" : "Offline"),
+		  LogicalDriveInformation->LogicalDriveSize,
+		  (LogicalDriveInformation->WriteBack
+		   ? "Write Back" : "Write Thru"));
+    }
+  DAC960_Info("\n", Controller);
+  return true;
+}
+
+
+/*
+  DAC960_RegisterBlockDevice registers the Block Device structures
+  associated with Controller.
+*/
+
+static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
+{
+  static void (*RequestFunctions[DAC960_MaxControllers])(void) =
+    { DAC960_RequestFunction0, DAC960_RequestFunction1,
+      DAC960_RequestFunction2, DAC960_RequestFunction3,
+      DAC960_RequestFunction4, DAC960_RequestFunction5,
+      DAC960_RequestFunction6, DAC960_RequestFunction7 };
+  int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
+  GenericDiskInfo_T *GenericDiskInfo;
+  int MinorNumber;
+  /*
+    Register the Block Device Major Number for this DAC960 Controller.
+  */
+  if (register_blkdev(MajorNumber, "rd", &DAC960_FileOperations) < 0)
+    {
+      DAC960_Error("UNABLE TO ACQUIRE MAJOR NUMBER %d - DETACHING\n",
+		   Controller, MajorNumber);
+      return false;
+    }
+  /*
+    Initialize the I/O Request Function.
+  */
+  blk_dev[MajorNumber].request_fn =
+    RequestFunctions[Controller->ControllerNumber];
+  /*
+    Initialize the Disk Partitions array, Partition Sizes array, Block Sizes
+    array, Max Sectors per Request array, and Max Segments per Request array.
+  */
+  for (MinorNumber = 0; MinorNumber < DAC960_MinorCount; MinorNumber++)
+    {
+      Controller->BlockSizes[MinorNumber] = BLOCK_SIZE;
+      Controller->MaxSectorsPerRequest[MinorNumber] =
+	Controller->MaxBlocksPerCommand;
+      Controller->MaxSegmentsPerRequest[MinorNumber] =
+	Controller->MaxScatterGatherSegments;
+    }
+  Controller->GenericDiskInfo.part = Controller->DiskPartitions;
+  Controller->GenericDiskInfo.sizes = Controller->PartitionSizes;
+  blksize_size[MajorNumber] = Controller->BlockSizes;
+  max_sectors[MajorNumber] = Controller->MaxSectorsPerRequest;
+  max_segments[MajorNumber] = Controller->MaxSegmentsPerRequest;
+  /*
+    Initialize Read Ahead to 128 sectors.
+  */
+  read_ahead[MajorNumber] = 128;
+  /*
+    Complete initialization of the Generic Disk Information structure.
+  */
+  Controller->GenericDiskInfo.major = MajorNumber;
+  Controller->GenericDiskInfo.major_name = "rd";
+  Controller->GenericDiskInfo.minor_shift = DAC960_MaxPartitionsBits;
+  Controller->GenericDiskInfo.max_p = DAC960_MaxPartitions;
+  Controller->GenericDiskInfo.max_nr = DAC960_MaxLogicalDrives;
+  Controller->GenericDiskInfo.init = DAC960_InitializeGenericDiskInfo;
+  Controller->GenericDiskInfo.nr_real = Controller->LogicalDriveCount;
+  Controller->GenericDiskInfo.real_devices = Controller;
+  Controller->GenericDiskInfo.next = NULL;
+  /*
+    Install the Generic Disk Information structure at the end of the list.
+  */
+  if ((GenericDiskInfo = gendisk_head) != NULL)
+    {
+      while (GenericDiskInfo->next != NULL)
+	GenericDiskInfo = GenericDiskInfo->next;
+      GenericDiskInfo->next = &Controller->GenericDiskInfo;
+    }
+  else gendisk_head = &Controller->GenericDiskInfo;
+  /*
+    Indicate the Block Device Registration completed successfully,
+  */
+  return true;
+}
+
+
+/*
+  DAC960_UnregisterBlockDevice unregisters the Block Device structures
+  associated with Controller.
+*/
+
+static void DAC960_UnregisterBlockDevice(DAC960_Controller_T *Controller)
+{
+  int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
+  /*
+    Unregister the Block Device Major Number for this DAC960 Controller.
+  */
+  unregister_blkdev(MajorNumber, "rd");
+  /*
+    Remove the I/O Request Function.
+  */
+  blk_dev[MajorNumber].request_fn = NULL;
+  /*
+    Remove the Disk Partitions array, Partition Sizes array, Block Sizes
+    array, Max Sectors per Request array, and Max Segments per Request array.
+  */
+  Controller->GenericDiskInfo.part = NULL;
+  Controller->GenericDiskInfo.sizes = NULL;
+  blk_size[MajorNumber] = NULL;
+  blksize_size[MajorNumber] = NULL;
+  max_sectors[MajorNumber] = NULL;
+  max_segments[MajorNumber] = NULL;
+  /*
+    Remove the Generic Disk Information structure from the list.
+  */
+  if (gendisk_head != &Controller->GenericDiskInfo)
+    {
+      GenericDiskInfo_T *GenericDiskInfo = gendisk_head;
+      while (GenericDiskInfo != NULL &&
+	     GenericDiskInfo->next != &Controller->GenericDiskInfo)
+	GenericDiskInfo = GenericDiskInfo->next;
+      if (GenericDiskInfo != NULL)
+	GenericDiskInfo->next = GenericDiskInfo->next->next;
+    }
+  else gendisk_head = Controller->GenericDiskInfo.next;
+}
+
+
+/*
+  DAC960_InitializeController initializes Controller.
+*/
+
+static void DAC960_InitializeController(DAC960_Controller_T *Controller)
+{
+  DAC960_AnnounceDriver(Controller);
+  if (DAC960_ReadControllerConfiguration(Controller) &&
+      DAC960_ReportControllerConfiguration(Controller) &&
+      DAC960_RegisterBlockDevice(Controller))
+    {
+      /*
+	Initialize the Command structures.
+      */
+      DAC960_Command_T *Commands = Controller->Commands;
+      int CommandIdentifier;
+      Controller->FreeCommands = NULL;
+      for (CommandIdentifier = 0;
+	   CommandIdentifier < Controller->DriverQueueDepth;
+	   CommandIdentifier++)
+	{
+	  Commands[CommandIdentifier].Controller = Controller;
+	  Commands[CommandIdentifier].Next = Controller->FreeCommands;
+	  Controller->FreeCommands = &Commands[CommandIdentifier];
+	}
+      /*
+	Initialize the Monitoring Timer.
+      */
+      init_timer(&Controller->MonitoringTimer);
+      Controller->MonitoringTimer.expires =
+	jiffies + DAC960_MonitoringTimerInterval;
+      Controller->MonitoringTimer.data = (unsigned long) Controller;
+      Controller->MonitoringTimer.function = DAC960_MonitoringTimerFunction;
+      add_timer(&Controller->MonitoringTimer);
+    }
+  else
+    {
+      free_irq(Controller->IRQ_Channel, Controller);
+      iounmap(Controller->MemoryMappedAddress);
+      DAC960_UnregisterBlockDevice(Controller);
+      DAC960_Controllers[Controller->ControllerNumber] = NULL;
+      kfree(Controller);
+    }
+}
+
+
+/*
+  DAC960_Initialize initializes the DAC960 Driver.
+*/
+
+void DAC960_Initialize(void)
+{
+  int ControllerNumber;
+  DAC960_DetectControllers(PCI_DEVICE_ID_MYLEX_DAC960P_V4);
+  DAC960_DetectControllers(PCI_DEVICE_ID_MYLEX_DAC960P_V3);
+  for (ControllerNumber = 0;
+       ControllerNumber < DAC960_ControllerCount;
+       ControllerNumber++)
+    if (DAC960_Controllers[ControllerNumber] != NULL)
+      DAC960_InitializeController(DAC960_Controllers[ControllerNumber]);
+}
+
+
+/*
+  DAC960_Finalize flushes all DAC960 caches before the system halts.
+*/
+
+void DAC960_Finalize(void)
+{
+  int ControllerNumber;
+  for (ControllerNumber = 0;
+       ControllerNumber < DAC960_ControllerCount;
+       ControllerNumber++)
+    {
+      DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
+      if (Controller == NULL) continue;
+      DAC960_Notice("Flushing Cache...", Controller);
+      DAC960_ExecuteType3(Controller, DAC960_Flush, NULL);
+      DAC960_Notice("done\n", Controller);
+    }
+}
+
+
+/*
+  DAC960_ProcessRequest attempts to remove one I/O Request from Controller's
+  I/O Request Queue and queues it to the Controller.  Command is either a
+  previously allocated Command to be reused, or NULL if a new Command is to
+  be allocated for this I/O Request.  It returns true if an I/O Request was
+  queued and false otherwise.
+*/
+
+static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller,
+				     DAC960_Command_T *Command)
+{
+  int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
+  IO_Request_T *Request = blk_dev[MajorNumber].current_request;
+  DAC960_CommandMailbox_T *CommandMailbox;
+  char *RequestBuffer;
+  if (Request == NULL || Request->rq_status == RQ_INACTIVE) return false;
+  if (Command == NULL)
+    Command = DAC960_AllocateCommand(Controller);
+  if (Command == NULL) return false;
+  DAC960_ClearCommand(Command);
+  if (Request->cmd == READ)
+    Command->CommandType = DAC960_ReadCommand;
+  else Command->CommandType = DAC960_WriteCommand;
+  Command->Semaphore = Request->sem;
+  Command->LogicalDriveNumber = DAC960_LogicalDriveNumber(Request->rq_dev);
+  Command->BlockNumber =
+    Request->sector
+    + Controller->GenericDiskInfo.part[MINOR(Request->rq_dev)].start_sect;
+  Command->BlockCount = Request->nr_sectors;
+  Command->SegmentCount = Request->nr_segments;
+  Command->BufferHeader = Request->bh;
+  RequestBuffer = Request->buffer;
+  Request->rq_status = RQ_INACTIVE;
+  blk_dev[MajorNumber].current_request = Request->next;
+  wake_up(&wait_for_request);
+  CommandMailbox = &Command->CommandMailbox;
+  if (Command->SegmentCount == 1)
+    {
+      if (Command->CommandType == DAC960_ReadCommand)
+	CommandMailbox->Type5.CommandOpcode = DAC960_Read;
+      else CommandMailbox->Type5.CommandOpcode = DAC960_Write;
+      CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
+      CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
+      CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
+      CommandMailbox->Type5.BusAddress = Virtual_to_Bus(RequestBuffer);
+    }
+  else
+    {
+      DAC960_ScatterGatherSegment_T
+	*ScatterGatherList = Command->ScatterGatherList;
+      BufferHeader_T *BufferHeader = Command->BufferHeader;
+      char *LastDataEndPointer = NULL;
+      int SegmentNumber = 0;
+      if (Command->CommandType == DAC960_ReadCommand)
+	CommandMailbox->Type5.CommandOpcode = DAC960_ReadWithOldScatterGather;
+      else
+	CommandMailbox->Type5.CommandOpcode = DAC960_WriteWithOldScatterGather;
+      CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
+      CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
+      CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
+      CommandMailbox->Type5.BusAddress = Virtual_to_Bus(ScatterGatherList);
+      CommandMailbox->Type5.ScatterGatherCount = Command->SegmentCount;
+      while (BufferHeader != NULL)
+	{
+	  if (BufferHeader->b_data == LastDataEndPointer)
+	    {
+	      ScatterGatherList[SegmentNumber-1].SegmentByteCount +=
+		BufferHeader->b_size;
+	      LastDataEndPointer += BufferHeader->b_size;
+	    }
+	  else
+	    {
+	      ScatterGatherList[SegmentNumber].SegmentDataPointer =
+		Virtual_to_Bus(BufferHeader->b_data);
+	      ScatterGatherList[SegmentNumber].SegmentByteCount =
+		BufferHeader->b_size;
+	      LastDataEndPointer = BufferHeader->b_data + BufferHeader->b_size;
+	      if (SegmentNumber++ > Controller->MaxScatterGatherSegments)
+		panic("DAC960: Scatter/Gather Segment Overflow\n");
+	    }
+	  BufferHeader = BufferHeader->b_reqnext;
+	}
+      if (SegmentNumber != Command->SegmentCount)
+	panic("DAC960: SegmentNumber != SegmentCount\n");
+    }
+  DAC960_QueueCommand(Command);
+  return true;
+}
+
+
+/*
+  DAC960_ProcessRequests attempts to remove as many I/O Requests as possible
+  from Controller's I/O Request Queue and queue them to the Controller.
+*/
+
+static inline void DAC960_ProcessRequests(DAC960_Controller_T *Controller)
+{
+  while (Controller->FreeCommands != NULL)
+    if (!DAC960_ProcessRequest(Controller, NULL)) break;
+}
+
+
+/*
+  DAC960_RequestFunction0 is the I/O Request Function for DAC960 Controller 0.
+*/
+
+static void DAC960_RequestFunction0(void)
+{
+  DAC960_Controller_T *Controller = DAC960_Controllers[0];
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+  /*
+    Process I/O Requests for Controller.
+   */
+  DAC960_ProcessRequests(Controller);
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+  DAC960_RequestFunction1 is the I/O Request Function for DAC960 Controller 1.
+*/
+
+static void DAC960_RequestFunction1(void)
+{
+  DAC960_Controller_T *Controller = DAC960_Controllers[1];
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+  /*
+    Process I/O Requests for Controller.
+   */
+  DAC960_ProcessRequests(Controller);
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+  DAC960_RequestFunction2 is the I/O Request Function for DAC960 Controller 2.
+*/
+
+static void DAC960_RequestFunction2(void)
+{
+  DAC960_Controller_T *Controller = DAC960_Controllers[2];
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+  /*
+    Process I/O Requests for Controller.
+   */
+  DAC960_ProcessRequests(Controller);
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+  DAC960_RequestFunction3 is the I/O Request Function for DAC960 Controller 3.
+*/
+
+static void DAC960_RequestFunction3(void)
+{
+  DAC960_Controller_T *Controller = DAC960_Controllers[3];
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+  /*
+    Process I/O Requests for Controller.
+   */
+  DAC960_ProcessRequests(Controller);
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+  DAC960_RequestFunction4 is the I/O Request Function for DAC960 Controller 4.
+*/
+
+static void DAC960_RequestFunction4(void)
+{
+  DAC960_Controller_T *Controller = DAC960_Controllers[4];
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+  /*
+    Process I/O Requests for Controller.
+   */
+  DAC960_ProcessRequests(Controller);
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+  DAC960_RequestFunction5 is the I/O Request Function for DAC960 Controller 5.
+*/
+
+static void DAC960_RequestFunction5(void)
+{
+  DAC960_Controller_T *Controller = DAC960_Controllers[5];
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+  /*
+    Process I/O Requests for Controller.
+   */
+  DAC960_ProcessRequests(Controller);
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+  DAC960_RequestFunction6 is the I/O Request Function for DAC960 Controller 6.
+*/
+
+static void DAC960_RequestFunction6(void)
+{
+  DAC960_Controller_T *Controller = DAC960_Controllers[6];
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+  /*
+    Process I/O Requests for Controller.
+   */
+  DAC960_ProcessRequests(Controller);
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+  DAC960_RequestFunction7 is the I/O Request Function for DAC960 Controller 7.
+*/
+
+static void DAC960_RequestFunction7(void)
+{
+  DAC960_Controller_T *Controller = DAC960_Controllers[7];
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
+  /*
+    Process I/O Requests for Controller.
+   */
+  DAC960_ProcessRequests(Controller);
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+}
+
+
+/*
+  DAC960_ReadWriteError prints an appropriate error message for Command when
+  an error occurs on a read or write operation.
+*/
+
+static void DAC960_ReadWriteError(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  char *CommandName = "UNKNOWN";
+  switch (Command->CommandType)
+    {
+    case DAC960_ReadCommand:
+    case DAC960_ReadRetryCommand:
+      CommandName = "READ";
+      break;
+    case DAC960_WriteCommand:
+    case DAC960_WriteRetryCommand:
+      CommandName = "WRITE";
+      break;
+    case DAC960_MonitoringCommand:
+    case DAC960_ImmediateCommand:
+      break;
+    }
+  switch (Command->CommandStatus)
+    {
+    case DAC960_IrrecoverableDataError:
+      DAC960_Error("Irrecoverable Data Error on %s:\n",
+		   Controller, CommandName);
+      break;
+    case DAC960_LogicalDriveNonexistentOrOffline:
+      break;
+    case DAC960_AccessBeyondEndOfLogicalDrive:
+      DAC960_Error("Attempt to Access Beyond End of Logical Drive "
+		   "on %s:\n", Controller, CommandName);
+      break;
+    case DAC960_BadDataEncountered:
+      DAC960_Error("Bad Data Encountered on %s:\n", Controller, CommandName);
+      break;
+    default:
+      DAC960_Error("Unexpected Error Status %04X on %s:\n",
+		   Controller, Command->CommandStatus, CommandName);
+      break;
+    }
+  DAC960_Error("  /dev/rd/c%dd%d:   absolute blocks %d..%d\n",
+	       Controller, Controller->ControllerNumber,
+	       Command->LogicalDriveNumber, Command->BlockNumber,
+	       Command->BlockNumber + Command->BlockCount - 1);
+  if (DAC960_PartitionNumber(Command->BufferHeader->b_rdev) > 0)
+    DAC960_Error("  /dev/rd/c%dd%dp%d: relative blocks %d..%d\n",
+		 Controller, Controller->ControllerNumber,
+		 Command->LogicalDriveNumber,
+		 DAC960_PartitionNumber(Command->BufferHeader->b_rdev),
+		 Command->BufferHeader->b_rsector,
+		 Command->BufferHeader->b_rsector + Command->BlockCount - 1);
+}
+
+
+/*
+  DAC960_ProcessCompletedBuffer performs completion processing for an
+  individual Buffer.
+*/
+
+static inline void DAC960_ProcessCompletedBuffer(BufferHeader_T *BufferHeader,
+						 boolean SuccessfulIO)
+{
+  mark_buffer_uptodate(BufferHeader, SuccessfulIO);
+  unlock_buffer(BufferHeader);
+}
+
+
+/*
+  DAC960_ProcessCompletedCommand performs completion processing for Command.
+*/
+
+static void DAC960_ProcessCompletedCommand(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  DAC960_CommandType_T CommandType = Command->CommandType;
+  DAC960_CommandStatus_T CommandStatus = Command->CommandStatus;
+  BufferHeader_T *BufferHeader = Command->BufferHeader;
+  if (CommandType == DAC960_ReadCommand ||
+      CommandType == DAC960_WriteCommand)
+    {
+      if (CommandStatus == DAC960_NormalCompletion)
+	{
+	  /*
+	    Perform completion processing for all buffers in this I/O Request.
+	  */
+	  while (BufferHeader != NULL)
+	    {
+	      BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
+	      BufferHeader->b_reqnext = NULL;
+	      DAC960_ProcessCompletedBuffer(BufferHeader, true);
+	      BufferHeader = NextBufferHeader;
+	    }
+	  /*
+	    Wake up requestor for swap file paging requests.
+	  */
+	  if (Command->Semaphore != NULL)
+	    {
+	      up(Command->Semaphore);
+	      Command->Semaphore = NULL;
+	    }
+	}
+      else if ((CommandStatus == DAC960_IrrecoverableDataError ||
+		CommandStatus == DAC960_BadDataEncountered) &&
+	       BufferHeader != NULL &&
+	       BufferHeader->b_reqnext != NULL)
+	{
+	  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+	  if (CommandType == DAC960_ReadCommand)
+	    {
+	      Command->CommandType = DAC960_ReadRetryCommand;
+	      CommandMailbox->Type5.CommandOpcode = DAC960_Read;
+	    }
+	  else
+	    {
+	      Command->CommandType = DAC960_WriteRetryCommand;
+	      CommandMailbox->Type5.CommandOpcode = DAC960_Write;
+	    }
+	  Command->BlockCount = BufferHeader->b_size >> DAC960_BlockSizeBits;
+	  CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
+	  CommandMailbox->Type5.BusAddress =
+	    Virtual_to_Bus(BufferHeader->b_data);
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+      else
+	{
+	  DAC960_ReadWriteError(Command);
+	  /*
+	    Perform completion processing for all buffers in this I/O Request.
+	  */
+	  while (BufferHeader != NULL)
+	    {
+	      BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
+	      BufferHeader->b_reqnext = NULL;
+	      DAC960_ProcessCompletedBuffer(BufferHeader, false);
+	      BufferHeader = NextBufferHeader;
+	    }
+	  /*
+	    Wake up requestor for swap file paging requests.
+	  */
+	  if (Command->Semaphore != NULL)
+	    {
+	      up(Command->Semaphore);
+	      Command->Semaphore = NULL;
+	    }
+	}
+    }
+  else if (CommandType == DAC960_ReadRetryCommand ||
+	   CommandType == DAC960_WriteRetryCommand)
+    {
+      BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
+      BufferHeader->b_reqnext = NULL;
+      /*
+	Perform completion processing for this single buffer.
+      */
+      if (CommandStatus == DAC960_NormalCompletion)
+	DAC960_ProcessCompletedBuffer(BufferHeader, true);
+      else
+	{
+	  DAC960_ReadWriteError(Command);
+	  DAC960_ProcessCompletedBuffer(BufferHeader, false);
+	}
+      if (NextBufferHeader != NULL)
+	{
+	  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+	  Command->BlockNumber +=
+	    BufferHeader->b_size >> DAC960_BlockSizeBits;
+	  Command->BlockCount =
+	    NextBufferHeader->b_size >> DAC960_BlockSizeBits;
+	  Command->BufferHeader = NextBufferHeader;
+	  CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
+	  CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
+	  CommandMailbox->Type5.BusAddress =
+	    Virtual_to_Bus(NextBufferHeader->b_data);
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+    }
+  else if (CommandType == DAC960_MonitoringCommand)
+    {
+      DAC960_CommandOpcode_T CommandOpcode =
+	Command->CommandMailbox.Common.CommandOpcode;
+      unsigned int OldCriticalLogicalDriveCount = 0;
+      unsigned int NewCriticalLogicalDriveCount = 0;
+      if (CommandOpcode == DAC960_Enquiry)
+	{
+	  DAC960_Enquiry_T *OldEnquiry =
+	    &Controller->Enquiry[Controller->EnquiryIndex];
+	  DAC960_Enquiry_T *NewEnquiry =
+	    &Controller->Enquiry[Controller->EnquiryIndex ^= 1];
+	  OldCriticalLogicalDriveCount = OldEnquiry->CriticalLogicalDriveCount;
+	  NewCriticalLogicalDriveCount = NewEnquiry->CriticalLogicalDriveCount;
+	  if (NewEnquiry->StatusFlags.DeferredWriteError !=
+	      OldEnquiry->StatusFlags.DeferredWriteError)
+	    DAC960_Critical("Deferred Write Error Flag is now %s\n", Controller,
+			    (NewEnquiry->StatusFlags.DeferredWriteError
+			     ? "TRUE" : "FALSE"));
+	  if ((NewCriticalLogicalDriveCount > 0 ||
+	       NewCriticalLogicalDriveCount != OldCriticalLogicalDriveCount) ||
+	      (NewEnquiry->OfflineLogicalDriveCount > 0 ||
+	       NewEnquiry->OfflineLogicalDriveCount !=
+	       OldEnquiry->OfflineLogicalDriveCount) ||
+	      (NewEnquiry->DeadDriveCount > 0 ||
+	       NewEnquiry->DeadDriveCount !=
+	       OldEnquiry->DeadDriveCount) ||
+	      (NewEnquiry->EventLogSequenceNumber !=
+	       OldEnquiry->EventLogSequenceNumber) ||
+	      (jiffies - Controller->SecondaryMonitoringTime
+		 >= DAC960_SecondaryMonitoringInterval))
+	    {
+	      Controller->NeedLogicalDriveInformation = true;
+	      Controller->NewEventLogSequenceNumber =
+		NewEnquiry->EventLogSequenceNumber;
+	      Controller->NeedDeviceStateInformation = true;
+	      Controller->DeviceStateChannel = 0;
+	      Controller->DeviceStateTargetID = 0;
+	      Controller->SecondaryMonitoringTime = jiffies;
+	    }
+	  if ((NewEnquiry->RebuildCount > 0 &&
+	      jiffies - Controller->RebuildLastReportTime
+		>= DAC960_RebuildStatusReportingInterval) ||
+	      NewEnquiry->RebuildCount != OldEnquiry->RebuildCount)
+	    Controller->NeedRebuildProgress = true;
+	}
+      else if (CommandOpcode == DAC960_GetLogicalDriveInformation)
+	{
+	  int LogicalDriveNumber;
+	  for (LogicalDriveNumber = 0;
+	       LogicalDriveNumber < Controller->LogicalDriveCount;
+	       LogicalDriveNumber++)
+	    {
+	      DAC960_LogicalDriveInformation_T *OldLogicalDriveInformation =
+		&Controller->LogicalDriveInformation
+			     [Controller->LogicalDriveInformationIndex]
+			     [LogicalDriveNumber];
+	      DAC960_LogicalDriveInformation_T *NewLogicalDriveInformation =
+		&Controller->LogicalDriveInformation
+			     [Controller->LogicalDriveInformationIndex ^ 1]
+			     [LogicalDriveNumber];
+	      if (NewLogicalDriveInformation->LogicalDriveState !=
+		  OldLogicalDriveInformation->LogicalDriveState)
+		DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
+				"is now %s\n", Controller,
+				LogicalDriveNumber,
+				Controller->ControllerNumber,
+				LogicalDriveNumber,
+				(NewLogicalDriveInformation->LogicalDriveState
+				 == DAC960_LogicalDrive_Online
+				 ? "ONLINE"
+				 : NewLogicalDriveInformation->LogicalDriveState
+				 == DAC960_LogicalDrive_Critical
+				 ? "CRITICAL" : "OFFLINE"));
+	      if (NewLogicalDriveInformation->WriteBack !=
+		  OldLogicalDriveInformation->WriteBack)
+		DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
+				"is now %s\n", Controller,
+				LogicalDriveNumber,
+				Controller->ControllerNumber,
+				LogicalDriveNumber,
+				(NewLogicalDriveInformation->WriteBack
+				 ? "WRITE BACK" : "WRITE THRU"));
+	    }
+	  Controller->LogicalDriveInformationIndex ^= 1;
+	}
+      else if (CommandOpcode == DAC960_PerformEventLogOperation)
+	{
+	  DAC960_EventLogEntry_T *EventLogEntry = &Controller->EventLogEntry;
+	  if (EventLogEntry->SequenceNumber ==
+	      Controller->OldEventLogSequenceNumber)
+	    {
+	      unsigned char SenseKey = EventLogEntry->SenseKey;
+	      unsigned char AdditionalSenseCode =
+		EventLogEntry->AdditionalSenseCode;
+	      unsigned char AdditionalSenseCodeQualifier =
+		EventLogEntry->AdditionalSenseCodeQualifier;
+	      if (SenseKey == 9 &&
+		  AdditionalSenseCode == 0x80 &&
+		  AdditionalSenseCodeQualifier < DAC960_EventMessagesCount)
+		DAC960_Critical("Physical Drive %d:%d %s\n", Controller,
+				EventLogEntry->Channel,
+				EventLogEntry->TargetID,
+				DAC960_EventMessages[
+				  AdditionalSenseCodeQualifier]);
+	      else if (!((SenseKey == 2 &&
+			  AdditionalSenseCode == 0x04 &&
+			  (AdditionalSenseCodeQualifier == 0x01 ||
+			   AdditionalSenseCodeQualifier == 0x02)) ||
+			 (SenseKey == 6 && AdditionalSenseCode == 0x29)))
+		DAC960_Critical("Physical Drive %d:%d Error Log: "
+				"Sense Key = %d, ASC = %02X, ASCQ = %02X\n",
+				Controller,
+				EventLogEntry->Channel,
+				EventLogEntry->TargetID,
+				SenseKey,
+				AdditionalSenseCode,
+				AdditionalSenseCodeQualifier);
+	    }
+	  Controller->OldEventLogSequenceNumber++;
+	}
+      else if (CommandOpcode == DAC960_GetDeviceState)
+	{
+	  DAC960_DeviceState_T *OldDeviceState =
+	    &Controller->DeviceState[Controller->DeviceStateIndex]
+				    [Controller->DeviceStateChannel]
+				    [Controller->DeviceStateTargetID];
+	  DAC960_DeviceState_T *NewDeviceState =
+	    &Controller->DeviceState[Controller->DeviceStateIndex ^ 1]
+				    [Controller->DeviceStateChannel]
+				    [Controller->DeviceStateTargetID];
+	  if (NewDeviceState->DeviceState != OldDeviceState->DeviceState)
+	    DAC960_Critical("Physical Drive %d:%d is now %s\n", Controller,
+			    Controller->DeviceStateChannel,
+			    Controller->DeviceStateTargetID,
+			    (NewDeviceState->DeviceState == DAC960_Device_Dead
+			     ? "DEAD"
+			     : NewDeviceState->DeviceState
+			       == DAC960_Device_WriteOnly
+			       ? "WRITE-ONLY"
+			       : NewDeviceState->DeviceState
+				 == DAC960_Device_Online
+				 ? "ONLINE" : "STANDBY"));
+	  if (++Controller->DeviceStateTargetID == DAC960_MaxTargets)
+	    {
+	      Controller->DeviceStateChannel++;
+	      Controller->DeviceStateTargetID = 0;
+	    }
+	}
+      else if (CommandOpcode == DAC960_GetRebuildProgress)
+	{
+	  unsigned int LogicalDriveNumber =
+	    Controller->RebuildProgress.LogicalDriveNumber;
+	  unsigned int LogicalDriveSize =
+	    Controller->RebuildProgress.LogicalDriveSize;
+	  unsigned int BlocksCompleted =
+	    LogicalDriveSize - Controller->RebuildProgress.RemainingBlocks;
+	  switch (CommandStatus)
+	    {
+	    case DAC960_NormalCompletion:
+	      DAC960_Critical("REBUILD IN PROGRESS: "
+			      "Logical Drive %d (/dev/rd/c%dd%d) "
+			      "%d%% completed\n",
+			      Controller, LogicalDriveNumber,
+			      Controller->ControllerNumber,
+			      LogicalDriveNumber,
+			      (100 * (BlocksCompleted >> 7))
+			      / (LogicalDriveSize >> 7));
+	      break;
+	    case DAC960_RebuildFailed_LogicalDriveFailure:
+	      DAC960_Critical("REBUILD FAILED due to "
+			      "LOGICAL DRIVE FAILURE\n", Controller);
+	      break;
+	    case DAC960_RebuildFailed_BadBlocksOnOther:
+	      DAC960_Critical("REBUILD FAILED due to "
+			      "BAD BLOCKS ON OTHER DRIVES\n", Controller);
+	      break;
+	    case DAC960_RebuildFailed_NewDriveFailed:
+	      DAC960_Critical("REBUILD FAILED due to "
+			      "FAILURE OF DRIVE BEING REBUILT\n", Controller);
+	      break;
+	    case DAC960_RebuildSuccessful:
+	      DAC960_Critical("REBUILD COMPLETED SUCCESSFULLY\n", Controller);
+	      break;
+	    case DAC960_NoRebuildOrCheckInProgress:
+	      break;
+	    }
+	  Controller->RebuildLastReportTime = jiffies;
+	}
+      if (Controller->NeedLogicalDriveInformation &&
+	  NewCriticalLogicalDriveCount >= OldCriticalLogicalDriveCount)
+	{
+	  Controller->NeedLogicalDriveInformation = false;
+	  Command->CommandMailbox.Type3.CommandOpcode =
+	    DAC960_GetLogicalDriveInformation;
+	  Command->CommandMailbox.Type3.BusAddress =
+	    Virtual_to_Bus(
+	      &Controller->LogicalDriveInformation
+			   [Controller->LogicalDriveInformationIndex ^ 1]);
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+      if (Controller->NewEventLogSequenceNumber
+	  - Controller->OldEventLogSequenceNumber > 0)
+	{
+	  Command->CommandMailbox.Type3E.CommandOpcode =
+	    DAC960_PerformEventLogOperation;
+	  Command->CommandMailbox.Type3E.OperationType =
+	    DAC960_GetEventLogEntry;
+	  Command->CommandMailbox.Type3E.OperationQualifier = 1;
+	  Command->CommandMailbox.Type3E.SequenceNumber =
+	    Controller->OldEventLogSequenceNumber;
+	  Command->CommandMailbox.Type3E.BusAddress =
+	    Virtual_to_Bus(&Controller->EventLogEntry);
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+      if (Controller->NeedDeviceStateInformation)
+	{
+	  while (Controller->DeviceStateChannel < Controller->Channels)
+	    {
+	      DAC960_DeviceState_T *OldDeviceState =
+		&Controller->DeviceState[Controller->DeviceStateIndex]
+					[Controller->DeviceStateChannel]
+					[Controller->DeviceStateTargetID];
+	      if (OldDeviceState->Present &&
+		  OldDeviceState->DeviceType == DAC960_DiskType)
+		{
+		  Command->CommandMailbox.Type3D.CommandOpcode =
+		    DAC960_GetDeviceState;
+		  Command->CommandMailbox.Type3D.Channel =
+		    Controller->DeviceStateChannel;
+		  Command->CommandMailbox.Type3D.TargetID =
+		    Controller->DeviceStateTargetID;
+		  Command->CommandMailbox.Type3D.BusAddress =
+		    Virtual_to_Bus(&Controller->DeviceState
+				      [Controller->DeviceStateIndex ^ 1]
+				      [Controller->DeviceStateChannel]
+				      [Controller->DeviceStateTargetID]);
+		  DAC960_QueueCommand(Command);
+		  return;
+		}
+	      if (++Controller->DeviceStateTargetID == DAC960_MaxTargets)
+		{
+		  Controller->DeviceStateChannel++;
+		  Controller->DeviceStateTargetID = 0;
+		}
+	    }
+	  Controller->NeedDeviceStateInformation = false;
+	  Controller->DeviceStateIndex ^= 1;
+	}
+      if (Controller->NeedRebuildProgress)
+	{
+	  Controller->NeedRebuildProgress = false;
+	  Command->CommandMailbox.Type3.CommandOpcode =
+	    DAC960_GetRebuildProgress;
+	  Command->CommandMailbox.Type3.BusAddress =
+	    Virtual_to_Bus(&Controller->RebuildProgress);
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+      if (Controller->NeedLogicalDriveInformation &&
+	  NewCriticalLogicalDriveCount < OldCriticalLogicalDriveCount)
+	{
+	  Controller->NeedLogicalDriveInformation = false;
+	  Command->CommandMailbox.Type3.CommandOpcode =
+	    DAC960_GetLogicalDriveInformation;
+	  Command->CommandMailbox.Type3.BusAddress =
+	    Virtual_to_Bus(
+	      &Controller->LogicalDriveInformation
+			   [Controller->LogicalDriveInformationIndex ^ 1]);
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+      Controller->MonitoringTimer.expires =
+	jiffies + DAC960_MonitoringTimerInterval;
+      add_timer(&Controller->MonitoringTimer);
+    }
+  else if (CommandType == DAC960_ImmediateCommand)
+    {
+      up(Command->Semaphore);
+      Command->Semaphore = NULL;
+      return;
+    }
+  else panic("DAC960: Unknown Command Type %d\n", CommandType);
+  /*
+    Queue a Monitoring Command to the Controller using the just completed
+    Command if one was deferred previously due to lack of a free Command when
+    the Monitoring Timer Function was called.
+  */
+  if (Controller->MonitoringCommandDeferred)
+    {
+      Controller->MonitoringCommandDeferred = false;
+      DAC960_QueueMonitoringCommand(Command);
+      return;
+    }
+  /*
+    Attempt to remove a new I/O Request from the Controller's I/O Request
+    Queue and queue it to the Controller using the just completed Command.
+    If there is no I/O Request to be queued, deallocate the Command.
+  */
+  if (!DAC960_ProcessRequest(Controller, Command))
+    DAC960_DeallocateCommand(Command);
+}
+
+
+/*
+  DAC960_InterruptHandler handles hardware interrupts from DAC960 Controllers.
+*/
+
+static void DAC960_InterruptHandler(int IRQ_Channel,
+				    void *DeviceIdentifier,
+				    Registers_T *InterruptRegisters)
+{
+  DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V4_StatusMailbox_T *NextStatusMailbox;
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
+  /*
+    Process Hardware Interrupts for Controller.
+  */
+  switch (Controller->ControllerType)
+    {
+    case DAC960_V4_Controller:
+      DAC960_V4_AcknowledgeInterrupt(ControllerBaseAddress);
+      NextStatusMailbox = Controller->NextStatusMailbox;
+      while (NextStatusMailbox->Fields.Valid)
+	{
+	  DAC960_CommandIdentifier_T CommandIdentifier =
+	    NextStatusMailbox->Fields.CommandIdentifier;
+	  DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier];
+	  Command->CommandStatus = NextStatusMailbox->Fields.CommandStatus;
+	  NextStatusMailbox->Word = 0;
+	  if (++NextStatusMailbox > Controller->LastStatusMailbox)
+	    NextStatusMailbox = Controller->FirstStatusMailbox;
+	  DAC960_ProcessCompletedCommand(Command);
+	}
+      Controller->NextStatusMailbox = NextStatusMailbox;
+      break;
+    case DAC960_V3_Controller:
+      while (DAC960_V3_StatusAvailableP(ControllerBaseAddress))
+	{
+	  DAC960_CommandIdentifier_T CommandIdentifier =
+	    DAC960_V3_ReadStatusCommandIdentifier(ControllerBaseAddress);
+	  DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier];
+	  Command->CommandStatus =
+	    DAC960_V3_ReadStatusRegister(ControllerBaseAddress);
+	  DAC960_V3_AcknowledgeInterrupt(ControllerBaseAddress);
+	  DAC960_V3_AcknowledgeStatus(ControllerBaseAddress);
+	  DAC960_ProcessCompletedCommand(Command);
+	}
+      break;
+    }
+  /*
+    Attempt to remove additional I/O Requests from the Controller's
+    I/O Request Queue and queue them to the Controller.
+  */
+  DAC960_ProcessRequests(Controller);
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
+}
+
+
+/*
+  DAC960_QueueMonitoringCommand queues a Monitoring Command to Controller.
+*/
+
+static void DAC960_QueueMonitoringCommand(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+  DAC960_ClearCommand(Command);
+  Command->CommandType = DAC960_MonitoringCommand;
+  CommandMailbox->Type3.CommandOpcode = DAC960_Enquiry;
+  CommandMailbox->Type3.BusAddress =
+    Virtual_to_Bus(&Controller->Enquiry[Controller->EnquiryIndex ^ 1]);
+  DAC960_QueueCommand(Command);
+}
+
+
+/*
+  DAC960_MonitoringTimerFunction is the timer function for monitoring
+  the status of DAC960 Controllers.
+*/
+
+static void DAC960_MonitoringTimerFunction(unsigned long TimerData)
+{
+  DAC960_Controller_T *Controller = (DAC960_Controller_T *) TimerData;
+  DAC960_Command_T *Command;
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+  /*
+    Queue a Status Monitoring Command for Controller;
+  */
+  Command = DAC960_AllocateCommand(Controller);
+  if (Command != NULL)
+    DAC960_QueueMonitoringCommand(Command);
+  else Controller->MonitoringCommandDeferred = true;
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+}
+
+
+/*
+  DAC960_Open is the Device Open Function for the DAC960 Driver.
+*/
+
+static int DAC960_Open(Inode_T *Inode, File_T *File)
+{
+  int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev);
+  int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev);
+  DAC960_Controller_T *Controller;
+  if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1)
+    return -ENXIO;
+  Controller = DAC960_Controllers[ControllerNumber];
+  if (Controller == NULL ||
+      LogicalDriveNumber > Controller->LogicalDriveCount - 1)
+    return -ENXIO;
+  if (Controller->LogicalDriveInformation
+		  [Controller->LogicalDriveInformationIndex]
+		  [LogicalDriveNumber] .LogicalDriveState
+      == DAC960_LogicalDrive_Offline)
+    return -ENXIO;
+  if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0)
+    return -ENXIO;
+  /*
+    Increment Controller and Logical Drive Usage Counts.
+  */
+  Controller->ControllerUsageCount++;
+  Controller->LogicalDriveUsageCount[LogicalDriveNumber]++;
+  return 0;
+}
+
+
+/*
+  DAC960_Release is the Device Release Function for the DAC960 Driver.
+*/
+
+static void DAC960_Release(Inode_T *Inode, File_T *File)
+{
+  int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev);
+  int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev);
+  DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
+  /*
+    Force any buffered data to be written.
+  */
+  fsync_dev(Inode->i_rdev);
+  /*
+    Decrement the Logical Drive and Controller Usage Counts.
+  */
+  Controller->LogicalDriveUsageCount[LogicalDriveNumber]--;
+  Controller->ControllerUsageCount--;
+}
+
+
+/*
+  DAC960_Ioctl is the Device Ioctl Function for the DAC960 Driver.
+*/
+
+static int DAC960_Ioctl(Inode_T *Inode, File_T *File,
+			unsigned int Request, unsigned long Argument)
+{
+  int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev);
+  int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev);
+  int PartitionNumber, ErrorCode;
+  unsigned short Cylinders;
+  DiskGeometry_T *Geometry;
+  DAC960_Controller_T *Controller;
+  if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1)
+    return -ENXIO;
+  Controller = DAC960_Controllers[ControllerNumber];
+  if (Controller == NULL ||
+      LogicalDriveNumber > Controller->LogicalDriveCount - 1)
+    return -ENXIO;
+  switch (Request)
+    {
+    case HDIO_GETGEO:
+      /* Get BIOS Disk Geometry. */
+      Geometry = (DiskGeometry_T *) Argument;
+      if (Geometry == NULL) return -EINVAL;
+      ErrorCode = verify_area(VERIFY_WRITE, Geometry, sizeof(DiskGeometry_T));
+      if (ErrorCode != 0) return ErrorCode;
+      Cylinders =
+	Controller->LogicalDriveInformation
+		    [Controller->LogicalDriveInformationIndex]
+		    [LogicalDriveNumber].LogicalDriveSize
+	/ (Controller->GeometryTranslationHeads *
+	   Controller->GeometryTranslationSectors);
+      put_user(Controller->GeometryTranslationHeads, &Geometry->heads);
+      put_user(Controller->GeometryTranslationSectors, &Geometry->sectors);
+      put_user(Cylinders, &Geometry->cylinders);
+      put_user(Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)]
+					  .start_sect, &Geometry->start);
+      return 0;
+    case BLKGETSIZE:
+      /* Get Device Size. */
+      if ((long *) Argument == NULL) return -EINVAL;
+      ErrorCode = verify_area(VERIFY_WRITE, (long *) Argument, sizeof(long));
+      if (ErrorCode != 0) return ErrorCode;
+      put_user(Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)].nr_sects,
+	       (long *) Argument);
+      return 0;
+    case BLKRAGET:
+      /* Get Read-Ahead. */
+      if ((int *) Argument == NULL) return -EINVAL;
+      ErrorCode = verify_area(VERIFY_WRITE, (int *) Argument, sizeof(int));
+      if (ErrorCode != 0) return ErrorCode;
+      put_user(read_ahead[MAJOR(Inode->i_rdev)], (int *) Argument);
+      return 0;
+    case BLKRASET:
+      /* Set Read-Ahead. */
+      if (!suser()) return -EACCES;
+      if (Argument > 256) return -EINVAL;
+      read_ahead[MAJOR(Inode->i_rdev)] = Argument;
+      return 0;
+    case BLKFLSBUF:
+      /* Flush Buffers. */
+      if (!suser()) return -EACCES;
+      fsync_dev(Inode->i_rdev);
+      invalidate_buffers(Inode->i_rdev);
+      return 0;
+    case BLKRRPART:
+      /* Re-Read Partition Table. */
+      if (!suser()) return -EACCES;
+      if (Controller->LogicalDriveUsageCount[LogicalDriveNumber] > 1)
+	return -EBUSY;
+      for (PartitionNumber = 0;
+	   PartitionNumber < DAC960_MaxPartitions;
+	   PartitionNumber++)
+	{
+	  KernelDevice_T Device = DAC960_KernelDevice(ControllerNumber,
+						      LogicalDriveNumber,
+						      PartitionNumber);
+	  int MinorNumber = DAC960_MinorNumber(LogicalDriveNumber,
+					       PartitionNumber);
+	  if (Controller->GenericDiskInfo.part[MinorNumber].nr_sects == 0)
+	    continue;
+	  /*
+	    Flush all changes and invalidate buffered state.
+	  */
+	  sync_dev(Device);
+	  invalidate_inodes(Device);
+	  invalidate_buffers(Device);
+	  /*
+	    Clear existing partition sizes.
+	  */
+	  if (PartitionNumber > 0)
+	    {
+	      Controller->GenericDiskInfo.part[MinorNumber].start_sect = 0;
+	      Controller->GenericDiskInfo.part[MinorNumber].nr_sects = 0;
+	    }
+	  /*
+	    Reset the Block Size so that the partition table can be read.
+	  */
+	  set_blocksize(Device, BLOCK_SIZE);
+	}
+      resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber);
+      return 0;
+    }
+  return -EINVAL;
+}
+
+
+/*
+  DAC960_GenericDiskInit is the Generic Disk Information Initialization
+  Function for the DAC960 Driver.
+*/
+
+static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo)
+{
+  DAC960_Controller_T *Controller =
+    (DAC960_Controller_T *) GenericDiskInfo->real_devices;
+  DAC960_LogicalDriveInformation_T *LogicalDriveInformation =
+    Controller->LogicalDriveInformation
+		[Controller->LogicalDriveInformationIndex];
+  int LogicalDriveNumber;
+  for (LogicalDriveNumber = 0;
+       LogicalDriveNumber < Controller->LogicalDriveCount;
+       LogicalDriveNumber++)
+    GenericDiskInfo->part[DAC960_MinorNumber(LogicalDriveNumber, 0)].nr_sects =
+      LogicalDriveInformation[LogicalDriveNumber].LogicalDriveSize;
+}
+
+
+/*
+  DAC960_Message prints Driver Messages.
+*/
+
+static void DAC960_Message(DAC960_MessageLevel_T MessageLevel,
+			   char *Format,
+			   DAC960_Controller_T *Controller,
+			   ...)
+{
+  static char Buffer[DAC960_LineBufferSize];
+  static boolean BeginningOfLine = true;
+  va_list Arguments;
+  int Length = 0;
+  va_start(Arguments, Controller);
+  Length = vsprintf(Buffer, Format, Arguments);
+  va_end(Arguments);
+  if (MessageLevel == DAC960_AnnounceLevel)
+    {
+      static int AnnouncementLines = 0;
+      strcpy(&Controller->MessageBuffer[Controller->MessageBufferLength],
+	     Buffer);
+      Controller->MessageBufferLength += Length;
+      if (++AnnouncementLines <= 2)
+	printk("%sDAC960: %s", DAC960_MessageLevelMap[MessageLevel], Buffer);
+    }
+  else if (MessageLevel == DAC960_InfoLevel)
+    {
+      strcpy(&Controller->MessageBuffer[Controller->MessageBufferLength],
+	     Buffer);
+      Controller->MessageBufferLength += Length;
+      if (BeginningOfLine)
+	{
+	  if (Buffer[0] != '\n' || Length > 1)
+	    printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
+		   Controller->ControllerNumber, Buffer);
+	}
+      else printk("%s", Buffer);
+    }
+  else
+    {
+      if (BeginningOfLine)
+	printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
+	       Controller->ControllerNumber, Buffer);
+      else printk("%s", Buffer);
+    }
+  BeginningOfLine = (Buffer[Length-1] == '\n');
+}
diff -urN linux-2.0.37-pre3/drivers/block/DAC960.h linux-2.0.37-pre4/drivers/block/DAC960.h
--- linux-2.0.37-pre3/drivers/block/DAC960.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.37-pre4/drivers/block/DAC960.h	2003-08-15 15:04:28.000000000 -0700
@@ -0,0 +1,1565 @@
+/*
+
+  Linux Driver for Mylex DAC960 PCI RAID Controllers
+
+  Copyright 1998 by Leonard N. Zubkoff <lnz@dandelion.com>
+
+  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.
+
+  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.
+
+*/
+
+
+/*
+  DAC960_DriverVersion protects the private portion of this file.
+*/
+
+#ifdef DAC960_DriverVersion
+
+
+/*
+  Define the maximum number of DAC960 Controllers supported by this driver.
+*/
+
+#define DAC960_MaxControllers			8
+
+
+/*
+  Define the maximum number of Controller Channels supported by this driver.
+*/
+
+#define DAC960_MaxChannels			3
+
+
+/*
+  Define the maximum number of Targets per Channel supported by this driver.
+*/
+
+#define DAC960_MaxTargets			16
+
+
+/*
+  Define the maximum number of Logical Drives supported by any DAC960 model.
+*/
+
+#define DAC960_MaxLogicalDrives			32
+
+
+/*
+  Define the maximum number of Partitions allowed for each Logical Drive.
+*/
+
+#define DAC960_MaxPartitions			8
+#define DAC960_MaxPartitionsBits		3
+
+
+/*
+  Define the maximum Driver Queue Depth and Controller Queue Depth supported
+  by any DAC960 model.
+*/
+
+#define DAC960_MaxDriverQueueDepth		127
+#define DAC960_MaxControllerQueueDepth		128
+
+
+/*
+  Define the maximum number of Scatter/Gather Segments supported by any
+  DAC960 model.
+*/
+
+#define DAC960_MaxScatterGatherSegments		33
+
+
+/*
+  Define the DAC960 Controller Monitoring Timer Interval.
+*/
+
+#define DAC960_MonitoringTimerInterval		(7 * HZ)
+
+
+/*
+  Define the DAC960 Controller Secondary Monitoring Interval.
+*/
+
+#define DAC960_SecondaryMonitoringInterval	(60 * HZ)
+
+
+/*
+  Define the DAC960 Controller Rebuild Status Reporting Interval.
+*/
+
+#define DAC960_RebuildStatusReportingInterval	(60 * HZ)
+
+
+/*
+  Define the number of Command Mailboxes and Status Mailboxes used by the
+  V4 Memory Mailbox Interface.
+*/
+
+#define DAC960_CommandMailboxCount		256
+#define DAC960_StatusMailboxCount		1024
+
+
+/*
+  Define macros to extract the Controller Number, Logical Drive Number, and
+  Partition Number from a Kernel Device, and to construct a Major Number, Minor
+  Number, and Kernel Device from the Controller Number, Logical Drive Number,
+  and Partition Number.  There is one Major Number assigned to each Controller.
+  The associated Minor Number is divided into the Logical Drive Number and
+  Partition Number.
+*/
+
+#define DAC960_ControllerNumber(Device) \
+  (MAJOR(Device) - DAC960_MAJOR)
+
+#define DAC960_LogicalDriveNumber(Device) \
+  (MINOR(Device) >> DAC960_MaxPartitionsBits)
+
+#define DAC960_PartitionNumber(Device) \
+  (MINOR(Device) & (DAC960_MaxPartitions - 1))
+
+#define DAC960_MajorNumber(ControllerNumber) \
+  (DAC960_MAJOR + (ControllerNumber))
+
+#define DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber) \
+   (((LogicalDriveNumber) << DAC960_MaxPartitionsBits) | (PartitionNumber))
+
+#define DAC960_MinorCount			(DAC960_MaxLogicalDrives \
+						 * DAC960_MaxPartitions)
+
+#define DAC960_KernelDevice(ControllerNumber,				       \
+			    LogicalDriveNumber,				       \
+			    PartitionNumber)				       \
+   MKDEV(DAC960_MajorNumber(ControllerNumber),				       \
+	 DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber))
+
+
+/*
+  Define the DAC960 Controller fixed Block Size and Block Size Bits.
+*/
+
+#define DAC960_BlockSize			512
+#define DAC960_BlockSizeBits			9
+
+
+/*
+  Define the Controller Line and Message Buffer Sizes.
+*/
+
+#define DAC960_LineBufferSize			100
+#define DAC960_MessageBufferSize		2048
+
+
+/*
+  Define the Driver Message Levels.
+*/
+
+typedef enum DAC960_MessageLevel
+{
+  DAC960_AnnounceLevel =			0,
+  DAC960_InfoLevel =				1,
+  DAC960_NoticeLevel =				2,
+  DAC960_WarningLevel =				3,
+  DAC960_ErrorLevel =				4,
+  DAC960_CriticalLevel =			5
+}
+DAC960_MessageLevel_T;
+
+static char
+  *DAC960_MessageLevelMap[] =
+    { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE,
+      KERN_WARNING, KERN_ERR, KERN_CRIT };
+
+
+/*
+  Define Driver Message macros.
+*/
+
+#define DAC960_Announce(Format, Arguments...) \
+  DAC960_Message(DAC960_AnnounceLevel, Format, ##Arguments)
+
+#define DAC960_Info(Format, Arguments...) \
+  DAC960_Message(DAC960_InfoLevel, Format, ##Arguments)
+
+#define DAC960_Notice(Format, Arguments...) \
+  DAC960_Message(DAC960_NoticeLevel, Format, ##Arguments)
+
+#define DAC960_Warning(Format, Arguments...) \
+  DAC960_Message(DAC960_WarningLevel, Format, ##Arguments)
+
+#define DAC960_Error(Format, Arguments...) \
+  DAC960_Message(DAC960_ErrorLevel, Format, ##Arguments)
+
+#define DAC960_Critical(Format, Arguments...) \
+  DAC960_Message(DAC960_CriticalLevel, Format, ##Arguments)
+
+
+/*
+  Define the types of DAC960 Controllers that are supported.
+*/
+
+typedef enum
+{
+  DAC960_V4_Controller =			1,	/* DAC960PTL/PJ/PG */
+  DAC960_V3_Controller =			2	/* DAC960PU/PD/PL */
+}
+DAC960_ControllerType_T;
+
+
+/*
+  Define a Boolean data type.
+*/
+
+typedef enum { false, true } __attribute__ ((packed)) boolean;
+
+
+/*
+  Define a 32 bit I/O Address data type.
+*/
+
+typedef unsigned int DAC960_IO_Address_T;
+
+
+/*
+  Define a 32 bit PCI Bus Address data type.
+*/
+
+typedef unsigned int DAC960_PCI_Address_T;
+
+
+/*
+  Define a 32 bit Bus Address data type.
+*/
+
+typedef unsigned int DAC960_BusAddress_T;
+
+
+/*
+  Define a 32 bit Byte Count data type.
+*/
+
+typedef unsigned int DAC960_ByteCount_T;
+
+
+/*
+  Define types for some of the structures that interface with the rest
+  of the Linux Kernel and I/O Subsystem.
+*/
+
+typedef struct buffer_head BufferHeader_T;
+typedef struct file File_T;
+typedef struct file_operations FileOperations_T;
+typedef struct gendisk GenericDiskInfo_T;
+typedef struct hd_geometry DiskGeometry_T;
+typedef struct hd_struct DiskPartition_T;
+typedef struct inode Inode_T;
+typedef kdev_t KernelDevice_T;
+typedef unsigned long ProcessorFlags_T;
+typedef struct pt_regs Registers_T;
+typedef struct request IO_Request_T;
+typedef struct semaphore Semaphore_T;
+typedef struct timer_list Timer_T;
+
+
+/*
+  Define the DAC960 V4 Controller Interface Register Offsets.
+*/
+
+#define DAC960_V4_RegisterWindowSize		0x2000
+
+typedef enum
+{
+  DAC960_V4_InboundDoorBellRegisterOffset =	0x0020,
+  DAC960_V4_OutboundDoorBellRegisterOffset =	0x002C,
+  DAC960_V4_InterruptMaskRegisterOffset =	0x0034,
+  DAC960_V4_CommandOpcodeRegisterOffset =	0x1000,
+  DAC960_V4_CommandIdentifierRegisterOffset =	0x1001,
+  DAC960_V4_MailboxRegister2Offset =		0x1002,
+  DAC960_V4_MailboxRegister3Offset =		0x1003,
+  DAC960_V4_MailboxRegister4Offset =		0x1004,
+  DAC960_V4_MailboxRegister5Offset =		0x1005,
+  DAC960_V4_MailboxRegister6Offset =		0x1006,
+  DAC960_V4_MailboxRegister7Offset =		0x1007,
+  DAC960_V4_MailboxRegister8Offset =		0x1008,
+  DAC960_V4_MailboxRegister9Offset =		0x1009,
+  DAC960_V4_MailboxRegister10Offset =		0x100A,
+  DAC960_V4_MailboxRegister11Offset =		0x100B,
+  DAC960_V4_MailboxRegister12Offset =		0x100C,
+  DAC960_V4_StatusCommandIdentifierRegOffset =	0x1018,
+  DAC960_V4_StatusRegisterOffset =		0x101A
+}
+DAC960_V4_RegisterOffsets_T;
+
+
+/*
+  Define the structure of the DAC960 V4 Inbound Door Bell Register.
+*/
+
+typedef union DAC960_V4_InboundDoorBellRegister
+{
+  unsigned int All;
+  struct {
+    boolean NewCommand:1;				/* Bit 0 */
+    boolean AcknowledgeStatus:1;			/* Bit 1 */
+    boolean SoftReset:1;				/* Bit 2 */
+    unsigned int :29;					/* Bits 3-31 */
+  } Write;
+  struct {
+    boolean MailboxFull:1;				/* Bit 0 */
+    unsigned int :31;					/* Bits 1-31 */
+  } Read;
+}
+DAC960_V4_InboundDoorBellRegister_T;
+
+
+/*
+  Define the structure of the DAC960 V4 Outbound Door Bell Register.
+*/
+
+typedef union DAC960_V4_OutboundDoorBellRegister
+{
+  unsigned int All;
+  struct {
+    boolean AcknowledgeInterrupt:1;			/* Bit 0 */
+    unsigned int :31;					/* Bits 1-31 */
+  } Write;
+  struct {
+    boolean StatusAvailable:1;				/* Bit 0 */
+    unsigned int :31;					/* Bits 1-31 */
+  } Read;
+}
+DAC960_V4_OutboundDoorBellRegister_T;
+
+
+/*
+  Define the structure of the DAC960 V4 Interrupt Mask Register.
+*/
+
+typedef union DAC960_V4_InterruptMaskRegister
+{
+  unsigned int All;
+  struct {
+    unsigned int MessageUnitInterruptMask1:2;		/* Bits 0-1 */
+    boolean DisableInterrupts:1;			/* Bit 2 */
+    unsigned int MessageUnitInterruptMask2:5;		/* Bits 3-7 */
+    unsigned int Reserved0:24;				/* Bits 8-31 */
+  } Bits;
+}
+DAC960_V4_InterruptMaskRegister_T;
+
+
+/*
+  Define the DAC960 V3 Controller Interface Register Offsets.
+*/
+
+#define DAC960_V3_RegisterWindowSize		0x80
+
+typedef enum
+{
+  DAC960_V3_CommandOpcodeRegisterOffset =	0x00,
+  DAC960_V3_CommandIdentifierRegisterOffset =	0x01,
+  DAC960_V3_MailboxRegister2Offset =		0x02,
+  DAC960_V3_MailboxRegister3Offset =		0x03,
+  DAC960_V3_MailboxRegister4Offset =		0x04,
+  DAC960_V3_MailboxRegister5Offset =		0x05,
+  DAC960_V3_MailboxRegister6Offset =		0x06,
+  DAC960_V3_MailboxRegister7Offset =		0x07,
+  DAC960_V3_MailboxRegister8Offset =		0x08,
+  DAC960_V3_MailboxRegister9Offset =		0x09,
+  DAC960_V3_MailboxRegister10Offset =		0x0A,
+  DAC960_V3_MailboxRegister11Offset =		0x0B,
+  DAC960_V3_MailboxRegister12Offset =		0x0C,
+  DAC960_V3_StatusCommandIdentifierRegOffset =	0x0D,
+  DAC960_V3_StatusRegisterOffset =		0x0E,
+  DAC960_V3_InboundDoorBellRegisterOffset =	0x40,
+  DAC960_V3_OutboundDoorBellRegisterOffset =	0x41,
+  DAC960_V3_InterruptEnableRegisterOffset =	0x43
+}
+DAC960_V3_RegisterOffsets_T;
+
+
+/*
+  Define the structure of the DAC960 V3 Inbound Door Bell Register.
+*/
+
+typedef union DAC960_V3_InboundDoorBellRegister
+{
+  unsigned char All;
+  struct {
+    boolean NewCommand:1;				/* Bit 0 */
+    boolean AcknowledgeStatus:1;			/* Bit 1 */
+    unsigned char :1;					/* Bit 2 */
+    boolean SoftReset:1;				/* Bit 3 */
+    unsigned char :4;					/* Bits 4-7 */
+  } Write;
+  struct {
+    boolean MailboxFull:1;				/* Bit 0 */
+    unsigned char :7;					/* Bits 1-7 */
+  } Read;
+}
+DAC960_V3_InboundDoorBellRegister_T;
+
+
+/*
+  Define the structure of the DAC960 V3 Outbound Door Bell Register.
+*/
+
+typedef union DAC960_V3_OutboundDoorBellRegister
+{
+  unsigned char All;
+  struct {
+    boolean AcknowledgeInterrupt:1;			/* Bit 0 */
+    unsigned char :7;					/* Bits 1-7 */
+  } Write;
+  struct {
+    boolean StatusAvailable:1;				/* Bit 0 */
+    unsigned char :7;					/* Bits 1-7 */
+  } Read;
+}
+DAC960_V3_OutboundDoorBellRegister_T;
+
+
+/*
+  Define the structure of the DAC960 V3 Interrupt Enable Register.
+*/
+
+typedef union DAC960_V3_InterruptEnableRegister
+{
+  unsigned char All;
+  struct {
+    boolean EnableInterrupts:1;				/* Bit 0 */
+    unsigned char :7;					/* Bits 1-7 */
+  } Bits;
+}
+DAC960_V3_InterruptEnableRegister_T;
+
+
+/*
+  Define the DAC960 Command Identifier type.
+*/
+
+typedef unsigned char DAC960_CommandIdentifier_T;
+
+
+/*
+  Define the DAC960 Command Opcodes.
+*/
+
+typedef enum
+{
+  /* I/O Commands */
+  DAC960_ReadExtended =				0x33,
+  DAC960_WriteExtended =			0x34,
+  DAC960_ReadAheadExtended =			0x35,
+  DAC960_ReadExtendedWithScatterGather =	0xB3,
+  DAC960_WriteExtendedWithScatterGather =	0xB4,
+  DAC960_Read =					0x36,
+  DAC960_ReadWithOldScatterGather =		0xB6,
+  DAC960_Write =				0x37,
+  DAC960_WriteWithOldScatterGather =		0xB7,
+  DAC960_DCDB =					0x04,
+  DAC960_DCDBWithScatterGather =		0x84,
+  DAC960_Flush =				0x0A,
+  /* Controller Status Related Commands */
+  DAC960_Enquiry =				0x53,
+  DAC960_Enquiry2 =				0x1C,
+  DAC960_GetLogicalDriveElement =		0x55,
+  DAC960_GetLogicalDriveInformation =		0x19,
+  DAC960_IOPortRead =				0x39,
+  DAC960_IOPortWrite =				0x3A,
+  DAC960_GetSDStats =				0x3E,
+  DAC960_GetPDStats =				0x3F,
+  DAC960_PerformEventLogOperation =		0x72,
+  /* Device Related Commands */
+  DAC960_StartDevice =				0x10,
+  DAC960_GetDeviceState =			0x50,
+  DAC960_StopChannel =				0x13,
+  DAC960_StartChannel =				0x12,
+  DAC960_ResetChannel =				0x1A,
+  /* Commands Associated with Data Consistency and Errors */
+  DAC960_Rebuild =				0x09,
+  DAC960_RebuildAsync =				0x16,
+  DAC960_CheckConsistency =			0x0F,
+  DAC960_CheckConsistencyAsync =		0x1E,
+  DAC960_RebuildStat =				0x0C,
+  DAC960_GetRebuildProgress =			0x27,
+  DAC960_RebuildControl =			0x1F,
+  DAC960_ReadBadBlockTable =			0x0B,
+  DAC960_ReadBadDataTable =			0x25,
+  DAC960_ClearBadDataTable =			0x26,
+  DAC960_GetErrorTable =			0x17,
+  DAC960_AddCapacityAsync =			0x2A,
+  /* Configuration Related Commands */
+  DAC960_ReadConfig2 =				0x3D,
+  DAC960_WriteConfig2 =				0x3C,
+  DAC960_ReadConfigurationOnDisk =		0x4A,
+  DAC960_WriteConfigurationOnDisk =		0x4B,
+  DAC960_ReadConfiguration =			0x4E,
+  DAC960_ReadBackupConfiguration =		0x4D,
+  DAC960_WriteConfiguration =			0x4F,
+  DAC960_AddConfiguration =			0x4C,
+  DAC960_ReadConfigurationLabel =		0x48,
+  DAC960_WriteConfigurationLabel =		0x49,
+  /* Firmware Upgrade Related Commands */
+  DAC960_LoadImage =				0x20,
+  DAC960_StoreImage =				0x21,
+  DAC960_ProgramImage =				0x22,
+  /* Diagnostic Commands */
+  DAC960_SetDiagnosticMode =			0x31,
+  DAC960_RunDiagnostic =			0x32,
+  /* Subsystem Service Commands */
+  DAC960_GetSubsystemData =			0x70,
+  DAC960_SetSubsystemParameters =		0x71
+}
+__attribute__ ((packed))
+DAC960_CommandOpcode_T;
+
+
+/*
+  Define the DAC960 Command Status Codes.
+*/
+
+#define DAC960_NormalCompletion			0x0000	/* Common */
+#define DAC960_CheckConditionReceived		0x0002	/* Common */
+#define DAC960_NoDeviceAtAddress		0x0102	/* Common */
+#define DAC960_InvalidDeviceAddress		0x0105	/* Common */
+#define DAC960_InvalidParameter			0x0105	/* Common */
+#define DAC960_IrrecoverableDataError		0x0001	/* I/O */
+#define DAC960_LogicalDriveNonexistentOrOffline	0x0002	/* I/O */
+#define DAC960_AccessBeyondEndOfLogicalDrive	0x0105	/* I/O */
+#define DAC960_BadDataEncountered		0x010C	/* I/O */
+#define DAC960_DeviceBusy			0x0008	/* DCDB */
+#define DAC960_DeviceNonresponsive		0x000E	/* DCDB */
+#define DAC960_CommandTerminatedAbnormally	0x000F	/* DCDB */
+#define DAC960_UnableToStartDevice		0x0002	/* Device */
+#define DAC960_InvalidChannelOrTarget		0x0105	/* Device */
+#define DAC960_ChannelBusy			0x0106	/* Device */
+#define DAC960_ChannelNotStopped		0x0002	/* Device */
+#define DAC960_AttemptToRebuildOnlineDrive	0x0002	/* Consistency */
+#define DAC960_RebuildBadBlocksEncountered	0x0003	/* Consistency */
+#define DAC960_NewDiskFailedDuringRebuild	0x0004	/* Consistency */
+#define DAC960_RebuildOrCheckAlreadyInProgress	0x0106	/* Consistency */
+#define DAC960_DependentDiskIsDead		0x0002	/* Consistency */
+#define DAC960_InconsistentBlocksFound		0x0003	/* Consistency */
+#define DAC960_InvalidOrNonredundantLogicalDrive 0x0105	/* Consistency */
+#define DAC960_NoRebuildOrCheckInProgress	0x0105	/* Consistency */
+#define DAC960_RebuildInProgress_DataValid	0x0000	/* Consistency */
+#define DAC960_RebuildFailed_LogicalDriveFailure 0x0002	/* Consistency */
+#define DAC960_RebuildFailed_BadBlocksOnOther	0x0003	/* Consistency */
+#define DAC960_RebuildFailed_NewDriveFailed	0x0004	/* Consistency */
+#define DAC960_RebuildSuccessful		0x0100	/* Consistency */
+#define DAC960_AddCapacityInProgress		0x0004	/* Consistency */
+#define DAC960_AddCapacityFailedOrSuspended	0x00F4	/* Consistency */
+#define DAC960_Config2ChecksumError		0x0002	/* Configuration */
+#define DAC960_ConfigurationSuspended		0x0106	/* Configuration */
+#define DAC960_FailedToConfigureNVRAM		0x0105	/* Configuration */
+#define DAC960_ConfigurationNotSavedStateChange	0x0106	/* Configuration */
+#define DAC960_SubsystemNotInstalled		0x0001	/* Subsystem */
+#define DAC960_SubsystemFailed			0x0002	/* Subsystem */
+#define DAC960_SubsystemBusy			0x0106	/* Subsystem */
+
+typedef unsigned short DAC960_CommandStatus_T;
+
+
+/*
+  Define the Enquiry reply structure.
+*/
+
+typedef struct DAC960_Enquiry
+{
+  unsigned char NumberOfLogicalDrives;			/* Byte 0 */
+  unsigned int :24;					/* Bytes 1-3 */
+  unsigned int LogicalDriveSizes[32];			/* Bytes 4-131 */
+  unsigned short FlashAge;				/* Bytes 132-133 */
+  struct {
+    boolean DeferredWriteError:1;			/* Byte 134 Bit 0 */
+    boolean BatteryLow:1;				/* Byte 134 Bit 1 */
+    unsigned char :6;					/* Byte 134 Bits 2-7 */
+  } StatusFlags;
+  unsigned char :8;					/* Byte 135 */
+  unsigned char MinorFirmwareVersion;			/* Byte 136 */
+  unsigned char MajorFirmwareVersion;			/* Byte 137 */
+  enum {
+    DAC960_NoStandbyRebuildOrCheckInProgress =			0x00,
+    DAC960_StandbyRebuildInProgress =				0x01,
+    DAC960_BackgroundRebuildInProgress =			0x02,
+    DAC960_BackgroundCheckInProgress =				0x03,
+    DAC960_StandbyRebuildCOmpletedWithError =			0xFF,
+    DAC960_BackgroundRebuildOrCheckFailed_DriveFailed =		0xF0,
+    DAC960_BackgroundRebuildOrCheckFailed_LogicalDriveFailed =	0xF1,
+    DAC960_BackgroundRebuildOrCheckFailed_OtherCauses =		0xF2,
+    DAC960_BackgroundRebuildOrCheckSuccessfullyTerminated =	0xF3
+  } __attribute__ ((packed)) RebuildFlag;		/* Byte 138 */
+  unsigned char MaxCommands;				/* Byte 139 */
+  unsigned char OfflineLogicalDriveCount;		/* Byte 140 */
+  unsigned char :8;					/* Byte 141 */
+  unsigned short EventLogSequenceNumber;		/* Bytes 142-143 */
+  unsigned char CriticalLogicalDriveCount;		/* Byte 144 */
+  unsigned int :24;					/* Bytes 145-147 */
+  unsigned char DeadDriveCount;				/* Byte 148 */
+  unsigned char :8;					/* Byte 149 */
+  unsigned char RebuildCount;				/* Byte 150 */
+  struct {
+    unsigned char :3;					/* Byte 151 Bits 0-2 */
+    boolean BatteryBackupUnitPresent:1;			/* Byte 151 Bit 3 */
+    unsigned char :3;					/* Byte 151 Bits 4-6 */
+    unsigned char :1;					/* Byte 151 Bit 7 */
+  } MiscFlags;
+  struct {
+    unsigned char TargetID;
+    unsigned char Channel;
+  } DeadDrives[21];					/* Bytes 152-194 */
+  unsigned char Reserved[62];				/* Bytes 195-255 */
+}
+__attribute__ ((packed))
+DAC960_Enquiry_T;
+
+
+/*
+  Define the Enquiry2 reply structure.
+*/
+
+typedef struct DAC960_Enquiry2
+{
+  struct {
+    enum {
+      DAC960_P_PD_PU =				0x01,
+      DAC960_PL =				0x02,
+      DAC960_PG =				0x10,
+      DAC960_PJ =				0x11,
+      DAC960_PTL_0 =				0x14,
+      DAC960_PTL_1 =				0x16
+    } __attribute__ ((packed)) SubModel;		/* Byte 0 */
+    unsigned char ActualChannels;			/* Byte 1 */
+    enum {
+      DAC960_FiveChannelBoard =			0x01,
+      DAC960_ThreeChannelBoard =		0x02,
+      DAC960_TwoChannelBoard =			0x03,
+      DAC960_ThreeChannelASIC_DAC =		0x04
+    } __attribute__ ((packed)) Model;			/* Byte 2 */
+    enum {
+      DAC960_EISA_Controller =			0x01,
+      DAC960_MicroChannel_Controller =		0x02,
+      DAC960_PCI_Controller =			0x03,
+      DAC960_SCSItoSCSI_Controller =		0x08
+    } __attribute__ ((packed)) ProductFamily;		/* Byte 3 */
+  } HardwareID;						/* Bytes 0-3 */
+  /* MajorVersion.MinorVersion-FirmwareType-TurnID */
+  struct {
+    unsigned char MajorVersion;				/* Byte 4 */
+    unsigned char MinorVersion;				/* Byte 5 */
+    unsigned char TurnID;				/* Byte 6 */
+    char FirmwareType;					/* Byte 7 */
+  } FirmwareID;						/* Bytes 4-7 */
+  unsigned char :8;					/* Byte 8 */
+  unsigned int :24;					/* Bytes 9-11 */
+  unsigned char ConfiguredChannels;			/* Byte 12 */
+  unsigned char ActualChannels;				/* Byte 13 */
+  unsigned char MaxTargets;				/* Byte 14 */
+  unsigned char MaxTags;				/* Byte 15 */
+  unsigned char MaxLogicalDrives;			/* Byte 16 */
+  unsigned char MaxArms;				/* Byte 17 */
+  unsigned char MaxSpans;				/* Byte 18 */
+  unsigned char :8;					/* Byte 19 */
+  unsigned int :32;					/* Bytes 20-23 */
+  unsigned int MemorySize;				/* Bytes 24-27 */
+  unsigned int CacheSize;				/* Bytes 28-31 */
+  unsigned int FlashMemorySize;				/* Bytes 32-35 */
+  unsigned int NonVolatileMemorySize;			/* Bytes 36-39 */
+  struct {
+    enum {
+      DAC960_DRAM =				0x00,
+      DAC960_EDO =				0x01
+    } __attribute__ ((packed)) RamType:3;		/* Byte 40 Bits 0-2 */
+    enum {
+      DAC960_None =				0x00,
+      DAC960_Parity =				0x01,
+      DAC960_ECC =				0x02
+    } __attribute__ ((packed)) ErrorCorrection:3;	/* Byte 40 Bits 3-5 */
+    boolean FastPageMode:1;				/* Byte 40 Bit 6 */
+    boolean LowPowerMemory:1;				/* Byte 40 Bit 7 */
+    unsigned char :8;					/* Bytes 41 */
+  } MemoryType;
+  unsigned short ClockSpeed;				/* Bytes 42-43 */
+  unsigned short MemorySpeed;				/* Bytes 44-45 */
+  unsigned short HardwareSpeed;				/* Bytes 46-47 */
+  unsigned int :32;					/* Bytes 48-51 */
+  unsigned int :32;					/* Bytes 52-55 */
+  unsigned char :8;					/* Byte 56 */
+  unsigned char :8;					/* Byte 57 */
+  unsigned short :16;					/* Bytes 58-59 */
+  unsigned short MaxCommands;				/* Bytes 60-61 */
+  unsigned short MaxScatterGatherEntries;		/* Bytes 62-63 */
+  unsigned short MaxDriveCommands;			/* Bytes 64-65 */
+  unsigned short MaxIODescriptors;			/* Bytes 66-67 */
+  unsigned short MaxCombinedSectors;			/* Bytes 68-69 */
+  unsigned char Latency;				/* Byte 70 */
+  unsigned char :8;					/* Byte 71 */
+  unsigned char SCSITimeout;				/* Byte 72 */
+  unsigned char :8;					/* Byte 73 */
+  unsigned short MinFreeLines;				/* Bytes 74-75 */
+  unsigned int :32;					/* Bytes 76-79 */
+  unsigned int :32;					/* Bytes 80-83 */
+  unsigned char RebuildRateConstant;			/* Byte 84 */
+  unsigned char :8;					/* Byte 85 */
+  unsigned char :8;					/* Byte 86 */
+  unsigned char :8;					/* Byte 87 */
+  unsigned int :32;					/* Bytes 88-91 */
+  unsigned int :32;					/* Bytes 92-95 */
+  unsigned short PhysicalDriveBlockSize;		/* Bytes 96-97 */
+  unsigned short LogicalDriveBlockSize;			/* Bytes 98-99 */
+  unsigned short MaxBlocksPerCommand;			/* Bytes 100-101 */
+  unsigned short BlockFactor;				/* Bytes 102-103 */
+  unsigned short CacheLineSize;				/* Bytes 104-105 */
+  struct {
+    enum {
+      DAC960_Narrow_8bit =			0x00,
+      DAC960_Wide_16bit =			0x01,
+      DAC960_Wide_32bit =			0x02
+    } __attribute__ ((packed)) BusWidth:2;		/* Byte 106 Bits 0-1 */
+    enum {
+      DAC960_Fast =				0x00,
+      DAC960_Ultra =				0x01,
+    } __attribute__ ((packed)) BusSpeed:2;		/* Byte 106 Bits 2-3 */
+    boolean Differential:1;				/* Byte 106 Bit 4 */
+    unsigned char :3;					/* Byte 106 Bits 5-7 */
+  } SCSICapability;
+  unsigned char :8;					/* Byte 107 */
+  unsigned int :32;					/* Bytes 108-111 */
+  unsigned short FirmwareBuildNumber;			/* Bytes 112-113 */
+  enum {
+    DAC960_AEMI =				0x01,
+    DAC960_OEM1 =				0x02,
+    DAC960_OEM2 =				0x04,
+    DAC960_OEM3 =				0x08,
+    DAC960_Conner =				0x10,
+    DAC960_SAFTE =				0x20
+  } __attribute__ ((packed)) FaultManagementType;	/* Byte 114 */
+  unsigned char :8;					/* Byte 115 */
+  struct {
+    boolean Clustering:1;				/* Byte 116 Bit 0 */
+    boolean MylexOnlineRAIDExpansion:1;			/* Byte 116 Bit 1 */
+    unsigned int :30;					/* Bytes 116-119 */
+  } FirmwareFeatures;
+  unsigned int :32;					/* Bytes 120-123 */
+  unsigned int :32;					/* Bytes 124-127 */
+}
+DAC960_Enquiry2_T;
+
+
+/*
+  Define the Get Logical Drive Information reply structure.
+*/
+
+typedef struct DAC960_LogicalDriveInformation
+{
+  unsigned int LogicalDriveSize;			/* Bytes 0-3 */
+  enum {
+    DAC960_LogicalDrive_Online =		0x03,
+    DAC960_LogicalDrive_Critical =		0x04,
+    DAC960_LogicalDrive_Offline =		0xFF
+  } __attribute__ ((packed)) LogicalDriveState;		/* Byte 4 */
+  unsigned char RAIDLevel:7;				/* Byte 5 Bits 0-6 */
+  boolean WriteBack:1;					/* Byte 5 Bit 7 */
+  unsigned int :16;					/* Bytes 6-7 */
+}
+DAC960_LogicalDriveInformation_T;
+
+
+/*
+  Define the Perform Event Log Operation Types.
+*/
+
+typedef enum
+{
+  DAC960_GetEventLogEntry =				0x00
+}
+__attribute__ ((packed))
+DAC960_PerformEventLogOpType_T;
+
+
+/*
+  Define the Get Event Log Entry reply structure.
+*/
+
+typedef struct DAC960_EventLogEntry
+{
+  unsigned char MessageType;				/* Byte 0 */
+  unsigned char MessageLength;				/* Byte 1 */
+  unsigned char TargetID:5;				/* Byte 2 Bits 0-4 */
+  unsigned char Channel:3;				/* Byte 2 Bits 5-7 */
+  unsigned char LogicalUnit:6;				/* Byte 3 Bits 0-5 */
+  unsigned char :2;					/* Byte 3 Bits 6-7 */
+  unsigned short SequenceNumber;			/* Bytes 4-5 */
+  unsigned char ErrorCode:7;				/* Byte 6 Bits 0-6 */
+  boolean Valid:1;					/* Byte 6 Bit 7 */
+  unsigned char SegmentNumber;				/* Byte 7 */
+  unsigned char SenseKey:4;				/* Byte 8 Bits 0-3 */
+  unsigned char :1;					/* Byte 8 Bit 4 */
+  boolean ILI:1;					/* Byte 8 Bit 5 */
+  boolean EOM:1;					/* Byte 8 Bit 6 */
+  boolean Filemark:1;					/* Byte 8 Bit 7 */
+  unsigned char Information[4];				/* Bytes 9-12 */
+  unsigned char AdditionalSenseLength;			/* Byte 13 */
+  unsigned char CommandSpecificInformation[4];		/* Bytes 14-17 */
+  unsigned char AdditionalSenseCode;			/* Byte 18 */
+  unsigned char AdditionalSenseCodeQualifier;		/* Byte 19 */
+  unsigned char Dummy[12];				/* Bytes 20-31 */
+}
+DAC960_EventLogEntry_T;
+
+#define DAC960_EventMessagesCount		13
+
+static char
+  *DAC960_EventMessages[DAC960_EventMessagesCount] =
+     { "killed because write recovery failed",
+       "killed because of SCSI bus reset failure",
+       "killed because of double check condition",
+       "killed because it was removed",
+       "killed because of gross error on SCSI chip",
+       "killed because of bad tag returned from drive",
+       "killed because of timeout on SCSI command",
+       "killed because of reset SCSI command issued from system",
+       "killed because busy or parity error count exceeded limit",
+       "killed because of 'kill drive' command from system",
+       "killed because of selection timeout",
+       "killed due to SCSI phase sequence error",
+       "killed due to unknown status" };
+
+
+/*
+  Define the Get Device State reply structure.
+*/
+
+typedef struct DAC960_DeviceState
+{
+  boolean Present:1;					/* Byte 0 Bit 0 */
+  unsigned char :7;					/* Byte 0 Bits 1-7 */
+  enum {
+    DAC960_OtherType =				0x00,
+    DAC960_DiskType =				0x01,
+    DAC960_SequentialType =			0x02,
+    DAC960_CDROM_or_WORM_Type =			0x03
+    } __attribute__ ((packed)) DeviceType:2;		/* Byte 1 Bits 0-1 */
+  boolean :1;						/* Byte 1 Bit 2 */
+  boolean Fast20:1;					/* Byte 1 Bit 3 */
+  boolean Sync:1;					/* Byte 1 Bit 4 */
+  boolean Fast:1;					/* Byte 1 Bit 5 */
+  boolean Wide:1;					/* Byte 1 Bit 6 */
+  boolean TaggedQueuingSupported:1;			/* Byte 1 Bit 7 */
+  enum {
+    DAC960_Device_Dead =			0x00,
+    DAC960_Device_WriteOnly =			0x02,
+    DAC960_Device_Online =			0x03,
+    DAC960_Device_Standby =			0x10
+  } __attribute__ ((packed)) DeviceState;		/* Byte 2 */
+  unsigned char :8;					/* Byte 3 */
+  unsigned char SynchronousMultiplier;			/* Byte 4 */
+  unsigned char SynchronousOffset:5;			/* Byte 5 Bits 0-4 */
+  unsigned char :3;					/* Byte 5 Bits 5-7 */
+  unsigned long DiskSize __attribute__ ((packed));	/* Bytes 6-9 */
+}
+DAC960_DeviceState_T;
+
+
+/*
+  Define the Get Rebuild Progress reply structure.
+*/
+
+typedef struct DAC960_RebuildProgress
+{
+  unsigned int LogicalDriveNumber;			/* Bytes 0-3 */
+  unsigned int LogicalDriveSize;			/* Bytes 4-7 */
+  unsigned int RemainingBlocks;				/* Bytes 8-11 */
+}
+DAC960_RebuildProgress_T;
+
+
+/*
+  Define the Config2 reply structure.
+*/
+
+typedef struct DAC960_Config2
+{
+  unsigned char :1;					/* Byte 0 Bit 0 */
+  boolean ActiveNegationEnabled:1;			/* Byte 0 Bit 1 */
+  unsigned char :5;					/* Byte 0 Bits 2-6 */
+  boolean NoRescanIfResetReceivedDuringScan:1;		/* Byte 0 Bit 7 */
+  boolean StorageWorksSupportEnabled:1;			/* Byte 1 Bit 0 */
+  boolean HewlettPackardSupportEnabled:1;		/* Byte 1 Bit 1 */
+  boolean NoDisconnectOnFirstCommand:1;			/* Byte 1 Bit 2 */
+  unsigned char :2;					/* Byte 1 Bits 3-4 */
+  boolean AEMI_ARM:1;					/* Byte 1 Bit 5 */
+  boolean AEMI_OFM:1;					/* Byte 1 Bit 6 */
+  unsigned char :1;					/* Byte 1 Bit 7 */
+  enum {
+    DAC960_OEMID_Mylex =			0x00,
+    DAC960_OEMID_IBM =				0x08,
+    DAC960_OEMID_HP =				0x0A,
+    DAC960_OEMID_DEC =				0x0C,
+    DAC960_OEMID_Siemens =			0x10,
+    DAC960_OEMID_Intel =			0x12
+  } __attribute__ ((packed)) OEMID;			/* Byte 2 */
+  unsigned char OEMModelNumber;				/* Byte 3 */
+  unsigned char PhysicalSector;				/* Byte 4 */
+  unsigned char LogicalSector;				/* Byte 5 */
+  unsigned char BlockFactor;				/* Byte 6 */
+  boolean ReadAheadEnabled:1;				/* Byte 7 Bit 0 */
+  boolean LowBIOSDelay:1;				/* Byte 7 Bit 1 */
+  unsigned char :2;					/* Byte 7 Bits 2-3 */
+  boolean ReassignRestrictedToOneSector:1;		/* Byte 7 Bit 4 */
+  unsigned char :1;					/* Byte 7 Bit 5 */
+  boolean ForceUnitAccessDuringWriteRecovery:1;		/* Byte 7 Bit 6 */
+  boolean EnableLeftSymmetricRAID5Algorithm:1;		/* Byte 7 Bit 7 */
+  unsigned char DefaultRebuildRate;			/* Byte 8 */
+  unsigned char :8;					/* Byte 9 */
+  unsigned char BlocksPerCacheLine;			/* Byte 10 */
+  unsigned char BlocksPerStripe;			/* Byte 11 */
+  struct {
+    enum {
+      DAC960_Async =				0x00,
+      DAC960_Sync_8MHz =			0x01,
+      DAC960_Sync_5MHz =			0x02,
+      DAC960_Sync_10or20MHz =			0x03	/* Bits 0-1 */
+    } __attribute__ ((packed)) Speed:2;
+    boolean Force8Bit:1;				/* Bit 2 */
+    boolean DisableFast20:1;				/* Bit 3 */
+    unsigned char :3;					/* Bits 4-6 */
+    boolean EnableTaggedQueuing:1;			/* Bit 7 */
+  } __attribute__ ((packed)) ChannelParameters[6];	/* Bytes 12-17 */
+  unsigned char SCSIInitiatorID;			/* Byte 18 */
+  unsigned char :8;					/* Byte 19 */
+  enum {
+    DAC960_StartupMode_ControllerSpinUp =	0x00,
+    DAC960_StartupMode_PowerOnSpinUp =		0x01
+  } __attribute__ ((packed)) StartupMode;		/* Byte 20 */
+  unsigned char SimultaneousDeviceSpinUpCount;		/* Byte 21 */
+  unsigned char SecondsDelayBetweenSpinUps;		/* Byte 22 */
+  unsigned char Reserved1[29];				/* Bytes 23-51 */
+  boolean BIOSDisabled:1;				/* Byte 52 Bit 0 */
+  boolean CDROMBootEnabled:1;				/* Byte 52 Bit 1 */
+  unsigned char :3;					/* Byte 52 Bits 2-4 */
+  enum {
+    DAC960_Geometry_128_32 =			0x00,
+    DAC960_Geometry_255_63 =			0x01,
+    DAC960_Geometry_Reserved1 =			0x02,
+    DAC960_Geometry_Reserved2 =			0x03
+  } __attribute__ ((packed)) DriveGeometry:2;		/* Byte 52 Bits 5-6 */
+  unsigned char :1;					/* Byte 52 Bit 7 */
+  unsigned char Reserved2[9];				/* Bytes 53-61 */
+  unsigned short Checksum;				/* Bytes 62-63 */
+}
+DAC960_Config2_T;
+
+
+/*
+  Define the Scatter/Gather List Type 1 32 Bit Address 32 Bit Byte Count
+  structure.
+*/
+
+typedef struct DAC960_ScatterGatherSegment
+{
+  DAC960_BusAddress_T SegmentDataPointer;		/* Bytes 0-3 */
+  DAC960_ByteCount_T SegmentByteCount;			/* Bytes 4-7 */
+}
+DAC960_ScatterGatherSegment_T;
+
+
+/*
+  Define the 13 Byte DAC960 Command Mailbox structure.  Bytes 13-15 are
+  not used.  The Command Mailbox structure is padded to 16 bytes for
+  efficient access.
+*/
+
+typedef union DAC960_CommandMailbox
+{
+  unsigned int Words[4];				/* Words 0-3 */
+  unsigned char Bytes[16];				/* Bytes 0-15 */
+  struct {
+    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
+    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
+    unsigned char Dummy[14];				/* Bytes 2-15 */
+  } __attribute__ ((packed)) Common;
+  struct {
+    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
+    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
+    unsigned char Dummy1[6];				/* Bytes 2-7 */
+    DAC960_BusAddress_T BusAddress;			/* Bytes 8-11 */
+    unsigned char Dummy2[4];				/* Bytes 12-15 */
+  } __attribute__ ((packed)) Type3;
+  struct {
+    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
+    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
+    unsigned char Channel;				/* Byte 2 */
+    unsigned char TargetID;				/* Byte 3 */
+    unsigned char Dummy1[4];				/* Bytes 4-7 */
+    DAC960_BusAddress_T BusAddress;			/* Bytes 8-11 */
+    unsigned char Dummy2[4];				/* Bytes 12-15 */
+  } __attribute__ ((packed)) Type3D;
+  struct {
+    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
+    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
+    DAC960_PerformEventLogOpType_T OperationType;	/* Byte 2 */
+    unsigned char OperationQualifier;			/* Byte 3 */
+    unsigned short SequenceNumber;			/* Bytes 4-5 */
+    unsigned char Dummy1[2];				/* Bytes 6-7 */
+    DAC960_BusAddress_T BusAddress;			/* Bytes 8-11 */
+    unsigned char Dummy2[4];				/* Bytes 12-15 */
+  } __attribute__ ((packed)) Type3E;
+  struct {
+    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
+    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
+    struct {
+      unsigned short TransferLength:11;			/* Bytes 2-3 */
+      unsigned char LogicalDriveNumber:5;		/* Byte 3 Bits 3-7 */
+    } __attribute__ ((packed)) LD;
+    unsigned int LogicalBlockAddress;			/* Bytes 4-7 */
+    DAC960_BusAddress_T BusAddress;			/* Bytes 8-11 */
+    unsigned char ScatterGatherCount:6;			/* Byte 12 Bits 0-5 */
+    enum {
+      DAC960_ScatterGather_32BitAddress_32BitByteCount =	0x0,
+      DAC960_ScatterGather_32BitAddress_16BitByteCount =	0x1,
+      DAC960_ScatterGather_32BitByteCount_32BitAddress =	0x2,
+      DAC960_ScatterGather_16BitByteCount_32BitAddress =	0x3
+    } __attribute__ ((packed)) ScatterGatherType:2;	/* Byte 12 Bits 6-7 */
+    unsigned char Dummy[3];				/* Bytes 13-15 */
+  } __attribute__ ((packed)) Type5;
+  struct {
+    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
+    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
+    unsigned char CommandOpcode2;			/* Byte 2 */
+    unsigned char :8;					/* Byte 3 */
+    DAC960_BusAddress_T CommandMailboxesBusAddress;	/* Bytes 4-7 */
+    DAC960_BusAddress_T StatusMailboxesBusAddress;	/* Bytes 8-11 */
+    unsigned char Dummy[4];				/* Bytes 12-15 */
+  } __attribute__ ((packed)) TypeX;
+}
+DAC960_CommandMailbox_T;
+
+
+/*
+  Define the DAC960 V4 Controller Command Mailbox structure.
+*/
+
+typedef DAC960_CommandMailbox_T DAC960_V4_CommandMailbox_T;
+
+
+/*
+  Define the DAC960 V4 Controller Status Mailbox structure.
+*/
+
+typedef union DAC960_V4_StatusMailbox
+{
+  unsigned int Word;					/* Bytes 0-3 */
+  struct {
+    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 0 */
+    unsigned char :7;					/* Byte 1 Bits 0-6 */
+    boolean Valid:1;					/* Byte 1 Bit 7 */
+    DAC960_CommandStatus_T CommandStatus;		/* Bytes 2-3 */
+  } Fields;
+}
+DAC960_V4_StatusMailbox_T;
+
+
+/*
+  Define the DAC960 Driver Command Types.
+*/
+
+typedef enum
+{
+  DAC960_ReadCommand =				1,
+  DAC960_WriteCommand =				2,
+  DAC960_ReadRetryCommand =			3,
+  DAC960_WriteRetryCommand =			4,
+  DAC960_MonitoringCommand =			5,
+  DAC960_ImmediateCommand =			6
+}
+DAC960_CommandType_T;
+
+
+/*
+  Define the DAC960 Driver Command structure.
+*/
+
+typedef struct DAC960_Command
+{
+  DAC960_CommandType_T CommandType;
+  DAC960_CommandMailbox_T CommandMailbox;
+  DAC960_CommandStatus_T CommandStatus;
+  struct DAC960_Controller *Controller;
+  struct DAC960_Command *Next;
+  Semaphore_T *Semaphore;
+  unsigned int LogicalDriveNumber;
+  unsigned int BlockNumber;
+  unsigned int BlockCount;
+  unsigned int SegmentCount;
+  BufferHeader_T *BufferHeader;
+  DAC960_ScatterGatherSegment_T
+    ScatterGatherList[DAC960_MaxScatterGatherSegments];
+}
+DAC960_Command_T;
+
+
+/*
+  Define the DAC960 Driver Controller structure.
+*/
+
+typedef struct DAC960_Controller
+{
+  void *BaseAddress;
+  void *MemoryMappedAddress;
+  DAC960_ControllerType_T ControllerType;
+  DAC960_IO_Address_T IO_Address;
+  DAC960_PCI_Address_T PCI_Address;
+  unsigned char ControllerNumber;
+  unsigned char ModelName[12];
+  unsigned char FullModelName[18];
+  unsigned char FirmwareVersion[14];
+  unsigned char Bus;
+  unsigned char Device;
+  unsigned char Function;
+  unsigned char IRQ_Channel;
+  unsigned char Channels;
+  unsigned char MemorySize;
+  unsigned char LogicalDriveCount;
+  unsigned char GeometryTranslationHeads;
+  unsigned char GeometryTranslationSectors;
+  unsigned short ControllerQueueDepth;
+  unsigned short DriverQueueDepth;
+  unsigned short MaxBlocksPerCommand;
+  unsigned short MaxScatterGatherSegments;
+  unsigned short StripeSize;
+  unsigned short SegmentSize;
+  unsigned short NewEventLogSequenceNumber;
+  unsigned short OldEventLogSequenceNumber;
+  unsigned short MessageBufferLength;
+  unsigned int ControllerUsageCount;
+  unsigned int EnquiryIndex;
+  unsigned int LogicalDriveInformationIndex;
+  unsigned int DeviceStateIndex;
+  unsigned int DeviceStateChannel;
+  unsigned int DeviceStateTargetID;
+  unsigned long SecondaryMonitoringTime;
+  unsigned long RebuildLastReportTime;
+  boolean SAFTE_FaultManagementEnabled;
+  boolean MonitoringCommandDeferred;
+  boolean NeedLogicalDriveInformation;
+  boolean NeedDeviceStateInformation;
+  boolean NeedRebuildProgress;
+  GenericDiskInfo_T GenericDiskInfo;
+  Timer_T MonitoringTimer;
+  DAC960_Command_T *FreeCommands;
+  DAC960_V4_CommandMailbox_T *FirstCommandMailbox;
+  DAC960_V4_CommandMailbox_T *LastCommandMailbox;
+  DAC960_V4_CommandMailbox_T *NextCommandMailbox;
+  DAC960_V4_CommandMailbox_T *PreviousCommandMailbox;
+  DAC960_V4_StatusMailbox_T *FirstStatusMailbox;
+  DAC960_V4_StatusMailbox_T *LastStatusMailbox;
+  DAC960_V4_StatusMailbox_T *NextStatusMailbox;
+  DAC960_Enquiry_T Enquiry[2];
+  DAC960_LogicalDriveInformation_T
+    LogicalDriveInformation[2][DAC960_MaxLogicalDrives];
+  DAC960_DeviceState_T DeviceState[2][DAC960_MaxChannels][DAC960_MaxTargets];
+  DAC960_EventLogEntry_T EventLogEntry;
+  DAC960_RebuildProgress_T RebuildProgress;
+  DAC960_Command_T Commands[DAC960_MaxDriverQueueDepth];
+  DiskPartition_T DiskPartitions[DAC960_MinorCount];
+  int LogicalDriveUsageCount[DAC960_MaxLogicalDrives];
+  int PartitionSizes[DAC960_MinorCount];
+  int BlockSizes[DAC960_MinorCount];
+  int MaxSectorsPerRequest[DAC960_MinorCount];
+  int MaxSegmentsPerRequest[DAC960_MinorCount];
+  char MessageBuffer[DAC960_MessageBufferSize];
+}
+DAC960_Controller_T;
+
+
+/*
+  DAC960_AcquireControllerLock acquires exclusive access to Controller.
+*/
+
+static inline
+void DAC960_AcquireControllerLock(DAC960_Controller_T *Controller,
+				  ProcessorFlags_T *ProcessorFlags)
+{
+  save_flags(*ProcessorFlags);
+  cli();
+}
+
+
+/*
+  DAC960_ReleaseControllerLock releases exclusive access to Controller.
+*/
+
+static inline
+void DAC960_ReleaseControllerLock(DAC960_Controller_T *Controller,
+				  ProcessorFlags_T *ProcessorFlags)
+{
+  restore_flags(*ProcessorFlags);
+}
+
+
+/*
+  DAC960_AcquireControllerLockRF acquires exclusive access to Controller,
+  but is only called from the request function when interrupts are disabled.
+*/
+
+static inline
+void DAC960_AcquireControllerLockRF(DAC960_Controller_T *Controller,
+				    ProcessorFlags_T *ProcessorFlags)
+{
+}
+
+
+/*
+  DAC960_ReleaseControllerLockRF releases exclusive access to Controller,
+  but is only called from the request function when interrupts are disabled.
+*/
+
+static inline
+void DAC960_ReleaseControllerLockRF(DAC960_Controller_T *Controller,
+				    ProcessorFlags_T *ProcessorFlags)
+{
+}
+
+
+/*
+  DAC960_AcquireControllerLockIH acquires exclusive access to Controller,
+  but is only called from the interrupt handler when interrupts are disabled.
+*/
+
+static inline
+void DAC960_AcquireControllerLockIH(DAC960_Controller_T *Controller,
+				    ProcessorFlags_T *ProcessorFlags)
+{
+}
+
+
+/*
+  DAC960_ReleaseControllerLockIH releases exclusive access to Controller,
+  but is only called from the interrupt handler when interrupts are disabled.
+*/
+
+static inline
+void DAC960_ReleaseControllerLockIH(DAC960_Controller_T *Controller,
+				    ProcessorFlags_T *ProcessorFlags)
+{
+}
+
+
+/*
+  Define inline functions to provide an abstraction for reading and writing the
+  DAC960 V4 Controller Interface Registers.
+*/
+
+static inline
+void DAC960_V4_NewCommand(void *ControllerBaseAddress)
+{
+  DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.NewCommand = true;
+  writel(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
+}
+
+static inline
+void DAC960_V4_AcknowledgeStatus(void *ControllerBaseAddress)
+{
+  DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.AcknowledgeStatus = true;
+  writel(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
+}
+
+static inline
+void DAC960_V4_SoftReset(void *ControllerBaseAddress)
+{
+  DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.SoftReset = true;
+  writel(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
+}
+
+static inline
+boolean DAC960_V4_MailboxFullP(void *ControllerBaseAddress)
+{
+  DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All =
+    readl(ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
+  return InboundDoorBellRegister.Read.MailboxFull;
+}
+
+static inline
+void DAC960_V4_AcknowledgeInterrupt(void *ControllerBaseAddress)
+{
+  DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  OutboundDoorBellRegister.All = 0;
+  OutboundDoorBellRegister.Write.AcknowledgeInterrupt = true;
+  writel(OutboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset);
+}
+
+static inline
+boolean DAC960_V4_StatusAvailableP(void *ControllerBaseAddress)
+{
+  DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  OutboundDoorBellRegister.All =
+    readl(ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset);
+  return OutboundDoorBellRegister.Read.StatusAvailable;
+}
+
+static inline
+void DAC960_V4_EnableInterrupts(void *ControllerBaseAddress)
+{
+  DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister;
+  InterruptMaskRegister.All = 0;
+  InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3;
+  InterruptMaskRegister.Bits.DisableInterrupts = false;
+  InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F;
+  writel(InterruptMaskRegister.All,
+	 ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset);
+}
+
+static inline
+void DAC960_V4_DisableInterrupts(void *ControllerBaseAddress)
+{
+  DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister;
+  InterruptMaskRegister.All = 0;
+  InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3;
+  InterruptMaskRegister.Bits.DisableInterrupts = true;
+  InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F;
+  writel(InterruptMaskRegister.All,
+	 ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset);
+}
+
+static inline
+boolean DAC960_V4_InterruptsEnabledP(void *ControllerBaseAddress)
+{
+  DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister;
+  InterruptMaskRegister.All =
+    readl(ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset);
+  return !InterruptMaskRegister.Bits.DisableInterrupts;
+}
+
+static inline
+void DAC960_V4_WriteCommandMailbox(DAC960_CommandMailbox_T *NextCommandMailbox,
+				   DAC960_CommandMailbox_T *CommandMailbox)
+{
+  NextCommandMailbox->Words[1] = CommandMailbox->Words[1];
+  NextCommandMailbox->Words[2] = CommandMailbox->Words[2];
+  NextCommandMailbox->Words[3] = CommandMailbox->Words[3];
+  NextCommandMailbox->Words[0] = CommandMailbox->Words[0];
+}
+
+static inline
+void DAC960_V4_WriteLegacyCommand(void *ControllerBaseAddress,
+				  DAC960_CommandMailbox_T *CommandMailbox)
+{
+  writel(CommandMailbox->Words[0],
+	 ControllerBaseAddress + DAC960_V4_CommandOpcodeRegisterOffset);
+  writel(CommandMailbox->Words[1],
+	 ControllerBaseAddress + DAC960_V4_MailboxRegister4Offset);
+  writel(CommandMailbox->Words[2],
+	 ControllerBaseAddress + DAC960_V4_MailboxRegister8Offset);
+  writeb(CommandMailbox->Bytes[12],
+	 ControllerBaseAddress + DAC960_V4_MailboxRegister12Offset);
+}
+
+static inline DAC960_CommandIdentifier_T
+DAC960_V4_ReadStatusCommandIdentifier(void *ControllerBaseAddress)
+{
+  return readb(ControllerBaseAddress
+	       + DAC960_V4_StatusCommandIdentifierRegOffset);
+}
+
+static inline DAC960_CommandStatus_T
+DAC960_V4_ReadStatusRegister(void *ControllerBaseAddress)
+{
+  return readw(ControllerBaseAddress + DAC960_V4_StatusRegisterOffset);
+}
+
+
+/*
+  Define inline functions to provide an abstraction for reading and writing the
+  DAC960 V3 Controller Interface Registers.
+*/
+
+static inline
+void DAC960_V3_NewCommand(void *ControllerBaseAddress)
+{
+  DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.NewCommand = true;
+  writeb(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
+}
+
+static inline
+void DAC960_V3_AcknowledgeStatus(void *ControllerBaseAddress)
+{
+  DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.AcknowledgeStatus = true;
+  writeb(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
+}
+
+static inline
+void DAC960_V3_SoftReset(void *ControllerBaseAddress)
+{
+  DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.SoftReset = true;
+  writeb(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
+}
+
+static inline
+boolean DAC960_V3_MailboxFullP(void *ControllerBaseAddress)
+{
+  DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All =
+    readb(ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
+  return InboundDoorBellRegister.Read.MailboxFull;
+}
+
+static inline
+void DAC960_V3_AcknowledgeInterrupt(void *ControllerBaseAddress)
+{
+  DAC960_V3_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  OutboundDoorBellRegister.All = 0;
+  OutboundDoorBellRegister.Write.AcknowledgeInterrupt = true;
+  writeb(OutboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_V3_OutboundDoorBellRegisterOffset);
+}
+
+static inline
+boolean DAC960_V3_StatusAvailableP(void *ControllerBaseAddress)
+{
+  DAC960_V3_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  OutboundDoorBellRegister.All =
+    readb(ControllerBaseAddress + DAC960_V3_OutboundDoorBellRegisterOffset);
+  return OutboundDoorBellRegister.Read.StatusAvailable;
+}
+
+static inline
+void DAC960_V3_EnableInterrupts(void *ControllerBaseAddress)
+{
+  DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister;
+  InterruptEnableRegister.All = 0;
+  InterruptEnableRegister.Bits.EnableInterrupts = true;
+  writeb(InterruptEnableRegister.All,
+	 ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset);
+}
+
+static inline
+void DAC960_V3_DisableInterrupts(void *ControllerBaseAddress)
+{
+  DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister;
+  InterruptEnableRegister.All = 0;
+  InterruptEnableRegister.Bits.EnableInterrupts = false;
+  writeb(InterruptEnableRegister.All,
+	 ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset);
+}
+
+static inline
+boolean DAC960_V3_InterruptsEnabledP(void *ControllerBaseAddress)
+{
+  DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister;
+  InterruptEnableRegister.All =
+    readb(ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset);
+  return InterruptEnableRegister.Bits.EnableInterrupts;
+}
+
+static inline
+void DAC960_V3_WriteCommandMailbox(void *ControllerBaseAddress,
+				   DAC960_CommandMailbox_T *CommandMailbox)
+{
+  writel(CommandMailbox->Words[0],
+	 ControllerBaseAddress + DAC960_V3_CommandOpcodeRegisterOffset);
+  writel(CommandMailbox->Words[1],
+	 ControllerBaseAddress + DAC960_V3_MailboxRegister4Offset);
+  writel(CommandMailbox->Words[2],
+	 ControllerBaseAddress + DAC960_V3_MailboxRegister8Offset);
+  writeb(CommandMailbox->Bytes[12],
+	 ControllerBaseAddress + DAC960_V3_MailboxRegister12Offset);
+}
+
+static inline DAC960_CommandIdentifier_T
+DAC960_V3_ReadStatusCommandIdentifier(void *ControllerBaseAddress)
+{
+  return readb(ControllerBaseAddress
+	       + DAC960_V3_StatusCommandIdentifierRegOffset);
+}
+
+static inline DAC960_CommandStatus_T
+DAC960_V3_ReadStatusRegister(void *ControllerBaseAddress)
+{
+  return readw(ControllerBaseAddress + DAC960_V3_StatusRegisterOffset);
+}
+
+
+/*
+  Virtual_to_Bus and Bus_to_Virtual map between Kernel Virtual Addresses
+  and PCI Bus Addresses.
+*/
+
+static inline DAC960_BusAddress_T Virtual_to_Bus(void *VirtualAddress)
+{
+  return (DAC960_BusAddress_T) virt_to_bus(VirtualAddress);
+}
+
+static inline void *Bus_to_Virtual(DAC960_BusAddress_T BusAddress)
+{
+  return (void *) bus_to_virt(BusAddress);
+}
+
+
+/*
+  Define compatibility macros between Linux 2.0 and Linux 2.1.
+*/
+
+#if LINUX_VERSION_CODE < 0x20100
+
+#define MODULE_PARM(Variable, Type)
+#define ioremap_nocache(Offset, Size)	vremap(Offset, Size)
+#define iounmap(Address)		vfree(Address)
+
+#endif
+
+
+/*
+  Define prototypes for the forward referenced DAC960 Driver Internal Functions.
+*/
+
+static void DAC960_RequestFunction0(void);
+static void DAC960_RequestFunction1(void);
+static void DAC960_RequestFunction2(void);
+static void DAC960_RequestFunction3(void);
+static void DAC960_RequestFunction4(void);
+static void DAC960_RequestFunction5(void);
+static void DAC960_RequestFunction6(void);
+static void DAC960_RequestFunction7(void);
+static void DAC960_InterruptHandler(int, void *, Registers_T *);
+static void DAC960_QueueMonitoringCommand(DAC960_Command_T *);
+static void DAC960_MonitoringTimerFunction(unsigned long);
+static int DAC960_Open(Inode_T *, File_T *);
+static void DAC960_Release(Inode_T *, File_T *);
+static int DAC960_Ioctl(Inode_T *, File_T *, unsigned int, unsigned long);
+static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *);
+static void DAC960_Message(DAC960_MessageLevel_T, char *,
+			   DAC960_Controller_T *, ...);
+
+
+#endif /* DAC960_DriverVersion */
diff -urN linux-2.0.37-pre3/drivers/block/genhd.c linux-2.0.37-pre4/drivers/block/genhd.c
--- linux-2.0.37-pre3/drivers/block/genhd.c	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/block/genhd.c	2003-08-15 15:04:28.000000000 -0700
@@ -99,6 +99,18 @@
 	    return buf;
 	  }
 #endif
+#if defined(CONFIG_BLK_CPQ_DA) || defined(CONFIG_BLK_CPQ_DA_MODULE)
+	if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= COMPAQ_SMART2_MAJOR+7) {
+		int ctlr = hd->major - COMPAQ_SMART2_MAJOR;
+		int disk = minor >> hd->minor_shift;
+		int part = minor & (( 1 << hd->minor_shift) - 1);
+		if (part == 0)
+			sprintf(buf, "%s/c%dd%d", maj, ctlr, disk);
+		else
+			sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, disk, part);
+		return buf;
+	}
+#endif
 	part = minor & ((1 << hd->minor_shift) - 1);
 	if (part)
 		sprintf(buf, "%s%c%d", maj, unit, part);
@@ -117,6 +129,11 @@
 		printk(" p%d", (minor & ((1 << hd->minor_shift) - 1)));
 	else
 #endif
+#if defined(CONFIG_BLK_CPQ_DA) || defined(CONFIG_BLK_CPQ_DA_MODULE)
+	if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= COMPAQ_SMART2_MAJOR+7) 
+		printk(" p%d", (minor & ((1 << hd->minor_shift) - 1)));
+	else
+#endif
 		printk(" %s", disk_name(hd, minor, buf));
 }
 
@@ -353,7 +370,9 @@
 				   && (q->sector & 63) == 1
 				   && (q->end_sector & 63) == 63) {
 					unsigned int heads = q->end_head + 1;
-					if (heads == 32 || heads == 64 || heads == 128 || heads == 255) {
+					if (heads == 32 || heads == 64 ||
+					    heads == 128 || heads == 240 ||
+					    heads == 255) {
 
 						(void) ide_xlate_1024(dev, heads, " [PTBL]");
 						break;
@@ -754,6 +773,7 @@
 void device_setup(void)
 {
 	extern void console_map_init(void);
+	extern void cpqarray_init(void);
 	struct gendisk *p;
 	int nr=0;
 
@@ -766,6 +786,9 @@
 #ifdef CONFIG_SCSI
 	scsi_dev_init();
 #endif
+#ifdef CONFIG_BLK_CPQ_DA
+	cpqarray_init();
+#endif
 #ifdef CONFIG_INET
 	net_dev_init();
 #endif
diff -urN linux-2.0.37-pre3/drivers/block/hd.c linux-2.0.37-pre4/drivers/block/hd.c
--- linux-2.0.37-pre3/drivers/block/hd.c	1998-07-13 13:47:27.000000000 -0700
+++ linux-2.0.37-pre4/drivers/block/hd.c	2003-08-15 15:04:28.000000000 -0700
@@ -871,6 +871,7 @@
 			restore_flags(flags);
 			return err;
 
+		case HDIO_OBSOLETE_IDENTITY:
 		case HDIO_GET_IDENTITY:
 			if (!arg)  return -EINVAL;
 			if (MINOR(inode->i_rdev) & 0x3F) return -EINVAL;
diff -urN linux-2.0.37-pre3/drivers/block/ida_cmd.h linux-2.0.37-pre4/drivers/block/ida_cmd.h
--- linux-2.0.37-pre3/drivers/block/ida_cmd.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.37-pre4/drivers/block/ida_cmd.h	2003-08-15 15:04:28.000000000 -0700
@@ -0,0 +1,340 @@
+/*
+ *    Disk Array driver for Compaq SMART2 Controllers
+ *    Copyright 1998 Compaq Computer Corporation
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *    NON INFRINGEMENT.  See the GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ *    If you want to make changes, improve or add functionality to this
+ *    driver, you'll probably need the Compaq Array Controller Interface
+ *    Specificiation (Document number ECG086/1198)
+ */
+#ifndef ARRAYCMD_H
+#define ARRAYCMD_H
+
+#include <asm/types.h>
+#if 0
+#include <linux/blkdev.h>
+#endif
+
+
+#define COMMAND_FIFO		0x04
+#define COMMAND_COMPLETE_FIFO	0x08
+#define INTR_MASK		0x0C
+#define INTR_STATUS		0x10
+#define INTR_PENDING		0x14
+
+#define FIFO_NOT_EMPTY		0x01
+#define FIFO_NOT_FULL		0x02
+
+#define BIG_PROBLEM		0x40
+#define LOG_NOT_CONF		2
+
+#pragma pack(1)
+typedef struct {
+	__u32	size;
+	__u32	addr;
+} sg_t;
+
+#define RCODE_NONFATAL	0x02
+#define RCODE_FATAL	0x04
+#define RCODE_INVREQ	0x10
+typedef struct {
+	__u16	next;
+	__u8	cmd;
+	__u8	rcode;
+	__u32	blk;
+	__u16	blk_cnt;
+	__u8	sg_cnt;
+	__u8	reserved;
+} rhdr_t;
+
+#define SG_MAX			32
+typedef struct {
+	rhdr_t	hdr;
+	sg_t	sg[SG_MAX];
+	__u32	bp;
+} rblk_t;
+
+typedef struct {
+	__u8	unit;
+	__u8	prio;
+	__u16	size;
+} chdr_t;
+
+#define CMD_RWREQ	0x00
+#define CMD_IOCTL_PEND	0x01
+#define CMD_IOCTL_DONE	0x02
+
+typedef struct cmdlist {
+	chdr_t	hdr;
+	rblk_t	req;
+	__u32	size;
+	int	retry_cnt;
+	__u32	busaddr;
+	int	ctlr;
+	struct cmdlist *prev;
+	struct cmdlist *next;
+	struct buffer_head *bh;
+	unsigned int type;
+	unsigned int expires;
+	unsigned long long start_time;
+} cmdlist_t;
+	
+#define ID_CTLR		0x11
+typedef struct {
+	__u8	nr_drvs;
+	__u32	cfg_sig;
+	__u32	firm_rev;
+	__u32	rom_rev;
+	__u8	hw_rev;
+	__u32	bb_rev;
+	__u32	drv_present_map;
+	__u32	ext_drv_map;
+	__u32	board_id;
+	__u8	cfg_error;
+	__u32	non_disk_bits;
+	__u8	bad_ram_addr;
+	__u8	cpu_rev;
+	__u8	pdpi_rev;
+	__u8	epic_rev;
+	__u8	wcxc_rev;
+	__u8	marketing_rev;
+	__u8	ctlr_flags;
+	__u8	host_flags;
+	__u8	expand_dis;
+	__u8	scsi_chips;
+	__u32	max_req_blocks;
+	__u32	ctlr_clock;
+	__u8	drvs_per_bus;
+	__u16	big_drv_present_map[8];
+	__u16	big_ext_drv_map[8];
+	__u16	big_non_disk_map[8];
+	__u16	task_flags;
+	__u8	icl_bus;
+	__u8	red_modes;
+	__u8	cur_red_mode;
+	__u8	red_ctlr_stat;
+	__u8	red_fail_reason;
+	__u8	reserved[403];
+} id_ctlr_t;
+
+typedef struct {
+	__u16	cyl;
+	__u8	heads;
+	__u8	xsig;
+	__u8	psectors;
+	__u16	wpre;
+	__u8	maxecc;
+	__u8	drv_ctrl;
+	__u16	pcyls;
+	__u8	pheads;
+	__u16	landz;
+	__u8	sect_per_track;
+	__u8	cksum;
+} drv_param_t;
+
+#define ID_LOG_DRV	0x10
+typedef struct {
+	__u16	blk_size;
+	__u32	nr_blks;
+	drv_param_t drv;
+	__u8	fault_tol;
+	__u8	reserved;
+	__u8	bios_disable;
+} id_log_drv_t;
+
+#define ID_LOG_DRV_EXT	0x18
+typedef struct {
+	__u32	log_drv_id;
+	__u8	log_drv_label[64];
+	__u8	reserved[418];
+} id_log_drv_ext_t;
+
+#define SENSE_LOG_DRV_STAT	0x12
+typedef struct {
+	__u8	status;
+	__u32	fail_map;
+	__u16	read_err[32];
+	__u16	write_err[32];
+	__u8	drv_err_data[256];
+	__u8	drq_timeout[32];
+	__u32	blks_to_recover;
+	__u8	drv_recovering;
+	__u16	remap_cnt[32];
+	__u32	replace_drv_map;
+	__u32	act_spare_map;
+	__u8	spare_stat;
+	__u8	spare_repl_map[32];
+	__u32	repl_ok_map;
+	__u8	media_exch;
+	__u8	cache_fail;
+	__u8	expn_fail;
+	__u8	unit_flags;
+	__u16	big_fail_map[8];
+	__u16	big_remap_map[8];
+	__u16	big_repl_map[8];
+	__u16	big_act_spare_map[8];
+	__u8	big_spar_repl_map[128];
+	__u16	big_repl_ok_map[8];
+	__u8	big_drv_rebuild;
+	__u8	reserved[36];
+} sense_log_drv_stat_t;
+
+#define START_RECOVER		0x13
+
+#define ID_PHYS_DRV		0x15
+typedef struct {
+	__u8	scsi_bus;
+	__u8	scsi_id;
+	__u16	blk_size;
+	__u32	nr_blks;
+	__u32	rsvd_blks;
+	__u8	drv_model[40];
+	__u8	drv_sn[40];
+	__u8	drv_fw[8];
+	__u8	scsi_iq_bits;
+	__u8	compaq_drv_stmp;
+	__u8	last_fail;
+	__u8	phys_drv_flags;
+	__u8	phys_drv_flags1;
+	__u8	scsi_lun;
+	__u8	phys_drv_flags2;
+	__u8	reserved;
+	__u32	spi_speed_rules;
+	__u8	phys_connector[2];
+	__u8	phys_box_on_bus;
+	__u8	phys_bay_in_box;
+} id_phys_drv_t;
+
+#define BLINK_DRV_LEDS		0x16
+typedef struct {
+	__u32	blink_duration;
+	__u32	reserved;
+	__u8	blink[256];
+	__u8	reserved1[248];
+} blink_drv_leds_t;
+
+#define SENSE_BLINK_LEDS	0x17
+typedef struct {
+	__u32	blink_duration;
+	__u32	btime_elap;
+	__u8	blink[256];
+	__u8	reserved1[248];
+} sense_blink_leds_t;
+
+#define IDA_READ		0x20
+#define IDA_WRITE		0x30
+#define IDA_WRITE_MEDIA		0x31
+#define RESET_TO_DIAG		0x40
+#define DIAG_PASS_THRU		0x41
+
+#define SENSE_CONFIG		0x50
+#define SET_CONFIG		0x51
+typedef struct {
+	__u32	cfg_sig;
+	__u16	compat_port;
+	__u8	data_dist_mode;
+	__u8	surf_an_ctrl;
+	__u16	ctlr_phys_drv;
+	__u16	log_unit_phys_drv;
+	__u16	fault_tol_mode;
+	__u8	phys_drv_param[16];
+	drv_param_t drv;
+	__u32	drv_asgn_map;
+	__u16	dist_factor;
+	__u32	spare_asgn_map;
+	__u8	reserved[6];
+	__u16	os;
+	__u8	ctlr_order;
+	__u8	extra_info;
+	__u32	data_offs;
+	__u8	parity_backedout_write_drvs;
+	__u8	parity_dist_mode;
+	__u8	parity_shift_fact;
+	__u8	bios_disable_flag;
+	__u32	blks_on_vol;
+	__u32	blks_per_drv;
+	__u8	scratch[16];
+	__u16	big_drv_map[8];
+	__u16	big_spare_map[8];
+	__u8	ss_source_vol;
+	__u8	mix_drv_cap_range;
+	struct {
+		__u16	big_drv_map[8];
+		__u32	blks_per_drv;
+		__u16	fault_tol_mode;
+		__u16	dist_factor;
+	} MDC_range[4];
+	__u8	reserved1[248];
+} config_t;
+
+#define BYPASS_VOL_STATE	0x52
+#define SS_CREATE_VOL		0x53
+#define CHANGE_CONFIG		0x54
+#define SENSE_ORIG_CONF		0x55
+#define REORDER_LOG_DRV		0x56
+typedef struct {
+	__u8	old_units[32];
+} reorder_log_drv_t;
+
+#define LABEL_LOG_DRV		0x57
+typedef struct {
+	__u8	log_drv_label[64];
+} label_log_drv_t;
+
+#define SS_TO_VOL		0x58
+	
+#define SET_SURF_DELAY		0x60
+typedef struct {
+	__u16	delay;
+	__u8	reserved[510];
+} surf_delay_t;
+
+#define SET_OVERHEAT_DELAY	0x61
+typedef struct {
+	__u16	delay;
+} overhead_delay_t;
+ 
+#define SET_MP_DELAY
+typedef struct {
+	__u16	delay;
+	__u8	reserved[510];
+} mp_delay_t;
+
+#define PASSTHRU_A	0x91
+typedef struct {
+	__u8	target;
+	__u8	bus;
+	__u8	lun;
+	__u32	timeout;
+	__u32	flags;
+	__u8	status;
+	__u8	error;
+	__u8	cdb_len;
+	__u8	sense_error;
+	__u8	sense_key;
+	__u32	sense_info;
+	__u8	sense_code;
+	__u8	sense_qual;
+	__u8	residual;
+	__u8	reserved[4];
+	__u8	cdb[12];	
+} scsi_param_t;
+
+#pragma pack()	
+
+#endif /* ARRAYCMD_H */
diff -urN linux-2.0.37-pre3/drivers/block/ida_ioctl.h linux-2.0.37-pre4/drivers/block/ida_ioctl.h
--- linux-2.0.37-pre3/drivers/block/ida_ioctl.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.37-pre4/drivers/block/ida_ioctl.h	2003-08-15 15:04:28.000000000 -0700
@@ -0,0 +1,80 @@
+/*
+ *    Disk Array driver for Compaq SMART2 Controllers
+ *    Copyright 1998 Compaq Computer Corporation
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *    NON INFRINGEMENT.  See the GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ *    If you want to make changes, improve or add functionality to this
+ *    driver, you'll probably need the Compaq Array Controller Interface
+ *    Specificiation (Document number ECG086/1198)
+ */
+#ifndef IDA_IOCTL_H
+#define IDA_IOCTL_H
+
+#include "ida_cmd.h"
+#include "cpqarray.h"
+
+#define IDAGETDRVINFO		0x27272828
+#define IDAPASSTHRU		0x28282929
+#define IDAGETCTLRSIG		0x29293030
+#define IDAREVALIDATEVOLS	0x30303131
+
+/*
+ * Normally, the ioctl determines the logical unit for this command by
+ * the major,minor number of the fd passed to ioctl.  If you need to send
+ * a command to a different/nonexistant unit (such as during config), you
+ * can override the normal behavior by setting the unit valid bit. (Normally,
+ * it should be zero) The controller to which the command is sent is still
+ * determined by the major number of the open device.
+ */
+
+#define UNITVALID	0x80
+typedef struct {
+	__u8	cmd;
+	__u8	rcode;
+	__u8	unit;
+
+/* currently, sg_cnt is assumed to be 1: only the 0th element of sg is used */
+	struct {
+		void	*addr;
+		size_t	size;
+	} sg[SG_MAX];
+	int	sg_cnt;
+
+	union ctlr_cmds {
+		drv_info_t		drv;
+		unsigned char		buf[512];
+
+		id_ctlr_t		id_ctlr;
+		drv_param_t		drv_param;
+		id_log_drv_t		id_log_drv;
+		id_log_drv_ext_t	id_log_drv_ext;
+		sense_log_drv_stat_t	sense_log_drv_stat;
+		id_phys_drv_t		id_phys_drv;
+		blink_drv_leds_t	blink_drv_leds;
+		sense_blink_leds_t	sense_blink_leds;
+		config_t		config;
+		reorder_log_drv_t	reorder_log_drv;
+		label_log_drv_t		label_log_drv;
+		surf_delay_t		surf_delay;
+		overhead_delay_t	overhead_delay;
+		mp_delay_t		mp_delay;
+		scsi_param_t		scsi_param;
+	} c;
+} ida_ioctl_t;
+
+#endif /* IDA_IOCTL_H */
diff -urN linux-2.0.37-pre3/drivers/block/ide.c linux-2.0.37-pre4/drivers/block/ide.c
--- linux-2.0.37-pre3/drivers/block/ide.c	1998-11-15 10:32:51.000000000 -0800
+++ linux-2.0.37-pre4/drivers/block/ide.c	2003-08-15 15:04:28.000000000 -0700
@@ -277,6 +277,12 @@
  *			fix MC_ERR handling
  *			fix mis-detection of NEC cdrom as floppy
  *			issue ATAPI reset and re-probe after "no response"
+ * Version 5.53.3	changes by Andrew D. Balsa to enable DMA mode 2 and
+ *			UDMA on SiS and TX chipsets.
+ * Version 5.53.4	moved Promise/33 auto-detection and DMA support
+ *			to trition.c and added UDMA to current DMA support.
+ *			update Promise Ultra33 and added AEC6210U/UF UDMA cards.
+ *			add configuration flag to allow booting of either card.
  *
  *  Some additional driver compile-time options are in ide.h
  *
@@ -607,11 +613,24 @@
 	unsigned long chs_sects   = id->cyls * id->heads * id->sectors;
 	unsigned long _10_percent = chs_sects / 10;
 
-	/* very large drives (8GB+) may lie about the number of cylinders */
-	if (id->cyls == 16383 && id->heads == 16 && id->sectors == 63 && lba_sects > chs_sects) {
+	/*
+	 * very large drives (8GB+) may lie about the number of cylinders
+	 * This is a split test for drives 8 Gig and Bigger only.
+	 */
+	if ((id->lba_capacity >= 16514064) && (id->cyls == 0x3fff) &&
+	    (id->heads == 16) && (id->sectors = 63)) {
 		id->cyls = lba_sects / (16 * 63); /* correct cyls */
 		return 1;	/* lba_capacity is our only option */
 	}
+	/*
+	 * very large drives (8GB+) may lie about the number of cylinders
+	 * This is a split test for drives less than 8 Gig only.
+	 */
+	if ((id->lba_capacity < 16514064) && (lba_sects > chs_sects) &&
+	    (id->heads == 16) && (id->sectors = 63)) {
+		id->cyls = lba_sects / (16 * 63); /* correct cyls */
+		return 1;	/* lba_capacity is our only option */
+	}	
 	/* perform a rough sanity check on lba_sects:  within 10% is "okay" */
 	if ((lba_sects - chs_sects) < _10_percent)
 		return 1;	/* lba_capacity is good */
@@ -649,6 +668,15 @@
 			drive->cyl = id->lba_capacity / (drive->head * drive->sect);
 			capacity = id->lba_capacity;
 			drive->select.b.lba = 1;
+#if 0
+			/*
+			 * This is the correct place to perform this task;
+			 * however, we do this later for reporting.
+			 */
+			if (*(int *)&id->cur_capacity0 != id->lba_capacity) {
+				*(int *)&id->cur_capacity0 = id->lba_capacity;
+			}
+#endif
 		}
 	}
 	return (capacity - drive->sect0);
@@ -2192,17 +2220,18 @@
 		case HDIO_GET_MULTCOUNT:
 			return write_fs_long(arg, drive->mult_count);
 
+		case HDIO_OBSOLETE_IDENTITY:
 		case HDIO_GET_IDENTITY:
 			if (!arg || (MINOR(inode->i_rdev) & PARTN_MASK))
 				return -EINVAL;
 			if (drive->id == NULL)
 				return -ENOMSG;
-			err = verify_area(VERIFY_WRITE, (char *)arg, sizeof(*drive->id));
+			err = verify_area(VERIFY_WRITE, (char *)arg, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142);
 			if (!err)
-				memcpy_tofs((char *)arg, (char *)drive->id, sizeof(*drive->id));
+				memcpy_tofs((char *)arg, (char *)drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142);
 			return err;
 
-			case HDIO_GET_NOWERR:
+		case HDIO_GET_NOWERR:
 			return write_fs_long(arg, drive->bad_wstat == BAD_R_STAT);
 
 		case HDIO_SET_DMA:
@@ -2545,9 +2574,8 @@
 		drive->sect    = drive->bios_sect = id->sectors;
 	}
 	/* Handle logical geometry translation by the drive */
-	if ((id->field_valid & 1) && id->cur_cyls && id->cur_heads
-	 && (id->cur_heads <= 16) && id->cur_sectors)
-	{
+	if ((id->field_valid & 1) && id->cur_cyls &&
+		id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
 		/*
 		 * Extract the physical drive geometry for our use.
 		 * Note that we purposely do *not* update the bios info.
@@ -2572,19 +2600,38 @@
 		}
 	}
 	/* Use physical geometry if what we have still makes no sense */
-	if ((!drive->head || drive->head > 16) && id->heads && id->heads <= 16) {
-		drive->cyl  = id->cyls;
-		drive->head = id->heads;
-		drive->sect = id->sectors;
+	if ((!drive->head || drive->head > 16) &&
+	    id->heads && id->heads <= 16) {
+		if ((id->lba_capacity > 16514064) || (id->cyls == 0x3fff)) {
+			id->cyls = ((int)(id->lba_capacity/(id->heads * id->sectors)));
+		}
+		drive->cyl  = id->cur_cyls    = id->cyls;
+		drive->head = id->cur_heads   = id->heads;
+		drive->sect = id->cur_sectors = id->sectors;
 	}
 
 	/* calculate drive capacity, and select LBA if possible */
-	(void) current_capacity (drive);
+	capacity = current_capacity (drive);
 
-	/* Correct the number of cyls if the bios value is too small */
-	if (drive->sect == drive->bios_sect && drive->head == drive->bios_head) {
-		if (drive->cyl > drive->bios_cyl)
-			drive->bios_cyl = drive->cyl;
+	/*
+	 * if possible, give fdisk access to more of the drive,
+	 * by correcting bios_cyls:
+	 */
+	if ((capacity >= (id->cyls * id->heads * id->sectors)) &&
+	    (!drive->forced_geom)) {
+		drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
+#ifdef DEBUG
+		printk("FDISK Fixing Geometry :: CHS=%d/%d/%d to CHS=%d/%d/%d\n",
+			drive->id->cur_cyls,
+			drive->id->cur_heads,
+			drive->id->cur_sectors,
+			drive->bios_cyl,
+			drive->bios_head,
+			drive->bios_sect);
+#endif
+		drive->id->cur_cyls    = drive->bios_cyl;
+		drive->id->cur_heads   = drive->bios_head;
+		drive->id->cur_sectors = drive->bios_sect;
 	}
 
 	if (!strncmp(id->model, "BMI ", 4) &&
@@ -2593,26 +2640,53 @@
 		drive->no_geom = 1;
 
 	printk ("%s: %.40s, %ldMB w/%dkB Cache, CHS=%d/%d/%d",
-	 drive->name, id->model, current_capacity(drive)/2048L, id->buf_size/2,
-	 drive->bios_cyl, drive->bios_head, drive->bios_sect);
+		drive->name, id->model,
+		capacity/2048L, id->buf_size/2,
+		drive->bios_cyl, drive->bios_head, drive->bios_sect);
 
 	drive->mult_count = 0;
 	if (id->max_multsect) {
+#if 1	/* original, pre IDE-NFG, per request of AC */
 		drive->mult_req = INITIAL_MULT_COUNT;
 		if (drive->mult_req > id->max_multsect)
 			drive->mult_req = id->max_multsect;
 		if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
 			drive->special.b.set_multmode = 1;
+#else
+		id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;
+		id->multsect_valid = id->multsect ? 1 : 0;
+		drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT;
+		drive->special.b.set_multmode = drive->mult_req ? 1 : 0;
+
+#endif
 	}
+
+	drive->no_io_32bit = id->dword_io ? 1 : 0;
+
 	if (drive->autotune != 2 && HWIF(drive)->dmaproc != NULL) {
 		if (!(HWIF(drive)->dmaproc(ide_dma_check, drive))) {
-			if ((id->field_valid & 4) && (id->dma_ultra & (id->dma_ultra >> 8) & 7))
-				printk(", UDMA");
-			else
+			if ((id->field_valid & 4) && (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
+				printk(", UDMA");	/* UDMA BIOS-enabled! */
+			} else if (id->field_valid & 4) {
+				printk(", (U)DMA");	/* Can be BIOS-enabled! */
+			} else {
 				printk(", DMA");
+			}
 		}
 	}
 	printk("\n");
+	if (drive->select.b.lba) {
+		if (*(int *)&id->cur_capacity0 != id->lba_capacity) {
+#ifdef DEBUG
+			printk("     CurSects=%d, LBASects=%d, ",
+				*(int *)&id->cur_capacity0, id->lba_capacity);
+#endif
+			*(int *)&id->cur_capacity0 = id->lba_capacity;
+#ifdef DEBUG
+			printk( "Fixed CurSects=%d\n", *(int *)&id->cur_capacity0);
+#endif
+		}
+	}
 }
 
 /*
@@ -3314,6 +3388,13 @@
  * an IDE disk drive, or if a geometry was "forced" on the commandline.
  * Returns 1 if the geometry translation was successful.
  */
+
+/*
+ * We update the values if the current CHS as determined by the kernel.
+ * This now allows for the hdparm tool to read the actual settings of the
+ * being used by the kernel.  This removes the need for doing guess
+ * translations based on the raw values of the drive.
+ */
 int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg)
 {
 	ide_drive_t *drive;
@@ -3321,14 +3402,38 @@
 	const byte *heads = head_vals;
 	unsigned long tracks;
 
-	if ((drive = get_info_ptr(i_rdev)) == NULL || drive->forced_geom)
+	if ((drive = get_info_ptr(i_rdev)) == NULL || drive->forced_geom) {
+		/*
+		 * Update the current 3D drive values.
+		 */
+		drive->id->cur_cyls	= drive->bios_cyl;
+		drive->id->cur_heads	= drive->bios_head;
+		drive->id->cur_sectors	= drive->bios_sect;
 		return 0;
+	}
 
-	if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63)
+	if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63) {
+		/*
+		 * Update the current 3D drive values.
+		 */
+		drive->id->cur_cyls	= drive->bios_cyl;
+		drive->id->cur_heads	= drive->bios_head;
+		drive->id->cur_sectors	= drive->bios_sect;
 		return 0;		/* we already have a translation */
+	}
 
 	printk("%s ", msg);
 
+	if (xparm < 0 && (drive->bios_cyl * drive->bios_head * drive->bios_sect) < (1024 * 16 * 63)) {
+		/*
+		 * Update the current 3D drive values.
+		 */
+		drive->id->cur_cyls	= drive->bios_cyl;
+		drive->id->cur_heads	= drive->bios_head;
+		drive->id->cur_sectors	= drive->bios_sect;
+		return 0;		/* small disk: no translation needed */
+	}
+
 	if (drive->id) {
 		drive->cyl  = drive->id->cyls;
 		drive->head = drive->id->heads;
@@ -3366,6 +3471,12 @@
 	}
 	drive->part[0].nr_sects = current_capacity(drive);
 	printk("[%d/%d/%d]", drive->bios_cyl, drive->bios_head, drive->bios_sect);
+	/*
+	 * Update the current 3D drive values.
+	 */
+	drive->id->cur_cyls	= drive->bios_cyl;
+	drive->id->cur_heads	= drive->bios_head;
+	drive->id->cur_sectors	= drive->bios_sect;
 	return 1;
 }
 
@@ -3535,43 +3646,6 @@
 }
 
 #endif /* defined(CONFIG_BLK_DEV_RZ1000) || defined(CONFIG_BLK_DEV_TRITON) */
-
-static void ide_probe_promise_20246(void)
-{
-	byte fn, bus;
-	unsigned short io[6], count = 0;
-	unsigned int reg, tmp, i;
-	ide_hwif_t *hwif;
-
-	memset(io, 0, 6 * sizeof(unsigned short));
-	if (pcibios_find_device(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, 0, &bus, &fn))
-		return;
-	printk("ide: Promise Technology IDE Ultra-DMA 33 on PCI bus %d function %d\n", bus, fn);
-	for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) {
-		pcibios_read_config_dword(bus, fn, reg, &tmp);
-		if (tmp & PCI_BASE_ADDRESS_SPACE_IO)
-			io[count++] = tmp & PCI_BASE_ADDRESS_IO_MASK;
-	}
-	for (i = 2; i < 4; i++) {
-		hwif = ide_hwifs + i;
-		if (hwif->chipset == ide_generic) {
-			printk("ide%d: overridden with command line parameter\n", i);
-			return;
-		}
-		tmp = (i - 2) * 2;
-		if (!io[tmp] || !io[tmp + 1]) {
-			printk("ide%d: invalid port address %x, %x -- aborting\n", i, io[tmp], io[tmp + 1]);
-			return;
-		}
-		hwif->io_base = io[tmp];
-		hwif->ctl_port = io[tmp + 1] + 2;
-		hwif->noprobe = 0;
-	}
-#ifdef CONFIG_BLK_DEV_TRITON
-	ide_init_promise (bus, fn, &ide_hwifs[2], &ide_hwifs[3], io[4]);
-#endif /* CONFIG_BLK_DEV_TRITON */
-}
-
 #endif /* CONFIG_PCI */
 
 /*
@@ -3599,11 +3673,20 @@
 		 * So instead, we search for PCI_DEVICE_ID_INTEL_82371_0,
 		 * and then add 1.
 		 */
+#ifdef CONFIG_BLK_DEV_OFFBOARD
+		ide_probe_pci (PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, &ide_init_triton, 0);
+		ide_probe_pci (PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF, &ide_init_triton, 0);
+#endif /* CONFIG_BLK_DEV_OFFBOARD */
 		ide_probe_pci (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371_0, &ide_init_triton, 1);
 		ide_probe_pci (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, &ide_init_triton, 0);
 		ide_probe_pci (PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, &ide_init_triton, 0);
+		ide_probe_pci (PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, &ide_init_triton, 0);
+		ide_probe_pci (PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, &ide_init_triton, 0);
+#ifndef CONFIG_BLK_DEV_OFFBOARD
+		ide_probe_pci (PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, &ide_init_triton, 0);
+		ide_probe_pci (PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF, &ide_init_triton, 0);
+#endif /* CONFIG_BLK_DEV_OFFBOARD */
 #endif /* CONFIG_BLK_DEV_TRITON */
-		ide_probe_promise_20246();
 	}
 #endif /* CONFIG_PCI */
 #ifdef CONFIG_BLK_DEV_CMD640
diff -urN linux-2.0.37-pre3/drivers/block/ide.h linux-2.0.37-pre4/drivers/block/ide.h
--- linux-2.0.37-pre3/drivers/block/ide.h	1998-11-15 10:32:52.000000000 -0800
+++ linux-2.0.37-pre4/drivers/block/ide.h	2003-08-15 15:04:28.000000000 -0700
@@ -429,7 +429,7 @@
 typedef enum {	ide_unknown,	ide_generic,	ide_triton,
 		ide_cmd640,	ide_dtc2278,	ide_ali14xx,
 		ide_qd6580,	ide_umc8672,	ide_ht6560b,
-		ide_promise,	ide_promise_udma }
+		ide_promise,	ide_udma }
 	hwif_chipset_t;
 
 typedef struct hwif_s {
@@ -743,5 +743,4 @@
 
 #ifdef CONFIG_BLK_DEV_TRITON
 void ide_init_triton (byte, byte);
-void ide_init_promise (byte bus, byte fn, ide_hwif_t *hwif0, ide_hwif_t *hwif1, unsigned short dma);
 #endif /* CONFIG_BLK_DEV_TRITON */
diff -urN linux-2.0.37-pre3/drivers/block/ll_rw_blk.c linux-2.0.37-pre4/drivers/block/ll_rw_blk.c
--- linux-2.0.37-pre3/drivers/block/ll_rw_blk.c	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/block/ll_rw_blk.c	2003-08-15 15:04:28.000000000 -0700
@@ -303,10 +303,9 @@
 	if (scsi_blk_major(major))
 		(dev->request_fn)();
 
-#ifdef CONFIG_BLK_DEV_DAC960
-	if (major >= DAC960_MAJOR+0 && major <= DAC960_MAJOR+7)
+	if ( (major >= DAC960_MAJOR+0 && major <= DAC960_MAJOR+7) ||
+	     (major >= COMPAQ_SMART2_MAJOR+0 && major <= COMPAQ_SMART2_MAJOR+7))
 	  (dev->request_fn)();
-#endif
 
 	sti();
 }
@@ -465,6 +464,14 @@
 	     case DAC960_MAJOR+5:
 	     case DAC960_MAJOR+6:
 	     case DAC960_MAJOR+7:
+	     case COMPAQ_SMART2_MAJOR+0:
+	     case COMPAQ_SMART2_MAJOR+1:
+	     case COMPAQ_SMART2_MAJOR+2:
+	     case COMPAQ_SMART2_MAJOR+3:
+	     case COMPAQ_SMART2_MAJOR+4:
+	     case COMPAQ_SMART2_MAJOR+5:
+	     case COMPAQ_SMART2_MAJOR+6:
+	     case COMPAQ_SMART2_MAJOR+7:
 		do {
 			if (req->sem)
 				continue;
diff -urN linux-2.0.37-pre3/drivers/block/Makefile linux-2.0.37-pre4/drivers/block/Makefile
--- linux-2.0.37-pre3/drivers/block/Makefile	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/block/Makefile	2003-08-15 15:04:28.000000000 -0700
@@ -156,7 +156,15 @@
   M_OBJS += raid5.o
   endif
 endif
+endif
 
+ifeq ($(CONFIG_BLK_CPQ_DA),y)
+L_OBJS += cpqarray.o proc_array.o
+else 
+  ifeq ($(CONFIG_BLK_CPQ_DA),m)
+  M_OBJS += cpqarray.o
+  endif
 endif
 
+
 include $(TOPDIR)/Rules.make
diff -urN linux-2.0.37-pre3/drivers/block/paride/Config.in linux-2.0.37-pre4/drivers/block/paride/Config.in
--- linux-2.0.37-pre3/drivers/block/paride/Config.in	1998-07-13 13:47:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/block/paride/Config.in	2003-08-15 15:04:28.000000000 -0700
@@ -16,6 +16,7 @@
 dep_tristate '    FIT TD-3000 protocol' CONFIG_PARIDE_FIT3 $CONFIG_PARIDE
 dep_tristate '    Shuttle EPAT/EPEZ protocol' CONFIG_PARIDE_EPAT $CONFIG_PARIDE
 dep_tristate '    Shuttle EPIA protocol' CONFIG_PARIDE_EPIA $CONFIG_PARIDE
+dep_tristate '    Freecom IQ ASIC-2 protocol' CONFIG_PARIDE_FRIQ $CONFIG_PARIDE
 dep_tristate '    FreeCom power protocol' CONFIG_PARIDE_FRPW $CONFIG_PARIDE
 dep_tristate '    KingByte KBIC-951A/971A protocols' CONFIG_PARIDE_KBIC $CONFIG_PARIDE
 dep_tristate '    KT PHd protocol' CONFIG_PARIDE_KTTI $CONFIG_PARIDE
diff -urN linux-2.0.37-pre3/drivers/block/paride/friq.c linux-2.0.37-pre4/drivers/block/paride/friq.c
--- linux-2.0.37-pre3/drivers/block/paride/friq.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.37-pre4/drivers/block/paride/friq.c	2003-08-15 15:04:28.000000000 -0700
@@ -0,0 +1,246 @@
+/* 
+	friq.c	(c) 1998    Grant R. Guenther <grant@torque.net>
+		            Under the terms of the GNU public license
+
+	friq.c is a low-level protocol driver for the Freecom "IQ"
+	parallel port IDE adapter. 
+	
+*/
+
+#define	FRIQ_VERSION	"1.00" 
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#include "paride.h"
+
+#define CMD(x)		w2(4);w0(0xff);w0(0xff);w0(0x73);w0(0x73);\
+			w0(0xc9);w0(0xc9);w0(0x26);w0(0x26);w0(x);w0(x);
+
+#define j44(l,h)	(((l>>4)&0x0f)|(h&0xf0))
+
+/* cont = 0 - access the IDE register file 
+   cont = 1 - access the IDE command set 
+*/
+
+static int  cont_map[2] = { 0x08, 0x10 };
+
+static int friq_read_regr( PIA *pi, int cont, int regr )
+
+{	int	h,l,r;
+
+	r = regr + cont_map[cont];
+
+	CMD(r);
+	w2(6); l = r1();
+	w2(4); h = r1();
+	w2(4); 
+
+	return j44(l,h);
+
+}
+
+static void friq_write_regr( PIA *pi, int cont, int regr, int val)
+
+{	int r;
+
+        r = regr + cont_map[cont];
+
+	CMD(r);
+	w0(val);
+	w2(5);w2(7);w2(5);w2(4);
+}
+
+static void friq_read_block_int( PIA *pi, char * buf, int count, int regr )
+
+{       int     h, l, k, ph;
+
+        switch(pi->mode) {
+
+        case 0: CMD(regr); 
+                for (k=0;k<count;k++) {
+                        w2(6); l = r1();
+                        w2(4); h = r1();
+                        buf[k] = j44(l,h);
+                }
+                w2(4);
+                break;
+
+        case 1: ph = 2;
+                CMD(regr+0xc0); 
+                w0(0xff);
+                for (k=0;k<count;k++) {
+                        w2(0xa4 + ph); 
+                        buf[k] = r0();
+                        ph = 2 - ph;
+                } 
+                w2(0xac); w2(0xa4); w2(4);
+                break;
+
+	case 2: CMD(regr+0x80);
+		for (k=0;k<count-2;k++) buf[k] = r4();
+		w2(0xac); w2(0xa4);
+		buf[count-2] = r4();
+		buf[count-1] = r4();
+		w2(4);
+		break;
+
+	case 3: CMD(regr+0x80);
+                for (k=0;k<(count/2)-1;k++) ((u16 *)buf)[k] = r4w();
+                w2(0xac); w2(0xa4);
+                buf[count-2] = r4();
+                buf[count-1] = r4();
+                w2(4);
+                break;
+
+	case 4: CMD(regr+0x80);
+                for (k=0;k<(count/4)-1;k++) ((u32 *)buf)[k] = r4l();
+                buf[count-4] = r4();
+                buf[count-3] = r4();
+                w2(0xac); w2(0xa4);
+                buf[count-2] = r4();
+                buf[count-1] = r4();
+                w2(4);
+                break;
+
+        }
+}
+
+static void friq_read_block( PIA *pi, char * buf, int count)
+
+{	friq_read_block_int(pi,buf,count,0x08);
+}
+
+static void friq_write_block( PIA *pi, char * buf, int count )
+ 
+{	int	k;
+
+	switch(pi->mode) {
+
+	case 0:
+	case 1: CMD(8); w2(5);
+        	for (k=0;k<count;k++) {
+			w0(buf[k]);
+			w2(7);w2(5);
+		}
+		w2(4);
+		break;
+
+	case 2: CMD(0xc8); w2(5);
+		for (k=0;k<count;k++) w4(buf[k]);
+		w2(4);
+		break;
+
+        case 3: CMD(0xc8); w2(5);
+                for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]);
+                w2(4);
+                break;
+
+        case 4: CMD(0xc8); w2(5);
+                for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]);
+                w2(4);
+                break;
+	}
+}
+
+static void friq_connect ( PIA *pi  )
+
+{       pi->saved_r0 = r0();
+        pi->saved_r2 = r2();
+	w2(4);
+}
+
+static void friq_disconnect ( PIA *pi )
+
+{       CMD(0x20);
+	w0(pi->saved_r0);
+        w2(pi->saved_r2);
+} 
+
+static int friq_test_proto( PIA *pi, char * scratch, int verbose )
+
+{       int     j, k, r;
+	int	e[2] = {0,0};
+
+	friq_connect(pi);
+	for (j=0;j<2;j++) {
+                friq_write_regr(pi,0,6,0xa0+j*0x10);
+                for (k=0;k<256;k++) {
+                        friq_write_regr(pi,0,2,k^0xaa);
+                        friq_write_regr(pi,0,3,k^0x55);
+                        if (friq_read_regr(pi,0,2) != (k^0xaa)) e[j]++;
+                        }
+                }
+	friq_disconnect(pi);
+
+	friq_connect(pi);
+        friq_read_block_int(pi,scratch,512,0x10);
+        r = 0;
+        for (k=0;k<128;k++) if (scratch[k] != k) r++;
+	friq_disconnect(pi);
+
+        if (verbose)  {
+            printk("%s: friq: port 0x%x, mode %d, test=(%d,%d,%d)\n",
+                   pi->device,pi->port,pi->mode,e[0],e[1],r);
+        }
+
+        return (r || (e[0] && e[1]));
+}
+
+
+static void friq_log_adapter( PIA *pi, char * scratch, int verbose )
+
+{       char    *mode_string[6] = {"4-bit","8-bit",
+				   "EPP-8","EPP-16","EPP-32"};
+
+        printk("%s: friq %s, Freecom IQ ASIC-2 adapter at 0x%x, ", pi->device,
+		FRIQ_VERSION,pi->port);
+        printk("mode %d (%s), delay %d\n",pi->mode,
+		mode_string[pi->mode],pi->delay);
+
+}
+
+static void friq_init_proto( PIA *pi)
+
+{       MOD_INC_USE_COUNT;
+}
+
+static void friq_release_proto( PIA *pi)
+
+{       MOD_DEC_USE_COUNT;
+}
+
+struct pi_protocol friq = {"friq",0,5,2,1,1,
+                           friq_write_regr,
+                           friq_read_regr,
+                           friq_write_block,
+                           friq_read_block,
+                           friq_connect,
+                           friq_disconnect,
+                           0,
+                           0,
+                           friq_test_proto,
+                           friq_log_adapter,
+                           friq_init_proto,
+                           friq_release_proto
+                          };
+
+
+#ifdef MODULE
+
+int     init_module(void)
+
+{       return pi_register( &friq ) - 1;
+}
+
+void    cleanup_module(void)
+
+{       pi_unregister( &friq );
+}
+
+#endif
+
+/* end of friq.c */
diff -urN linux-2.0.37-pre3/drivers/block/paride/frpw.c linux-2.0.37-pre4/drivers/block/paride/frpw.c
--- linux-2.0.37-pre3/drivers/block/paride/frpw.c	1998-11-15 10:32:52.000000000 -0800
+++ linux-2.0.37-pre4/drivers/block/paride/frpw.c	2003-08-15 15:04:28.000000000 -0700
@@ -5,6 +5,12 @@
 	frpw.c is a low-level protocol driver for the Freecom "Power"
 	parallel port IDE adapter.
 	
+	Some applications of this adapter may require a "printer" reset
+	prior to loading the driver.  This can be done by loading and
+	unloading the "lp" driver, or it can be done by this driver
+	if you define FRPW_HARD_RESET.  The latter is not recommended
+	as it may upset devices on other ports.
+
 */
 
 /* Changes:
@@ -13,10 +19,11 @@
 			       fix chip detect
 			       added EPP-16 and EPP-32
 	1.02    GRG 1998.09.23 added hard reset to initialisation process
+	1.03    GRG 1998.12.14 made hard reset conditional
 
 */
 
-#define	FRPW_VERSION	"1.02" 
+#define	FRPW_VERSION	"1.03" 
 
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -185,8 +192,10 @@
 
 {	int olddelay, a, b;
 
+#ifdef FRPW_HARD_RESET
         w0(0); w2(8); udelay(50); w2(0xc);   /* parallel bus reset */
         udelay(1500000);
+#endif
 
 	olddelay = pi->delay;
 	pi->delay = 10;
diff -urN linux-2.0.37-pre3/drivers/block/paride/jumbo linux-2.0.37-pre4/drivers/block/paride/jumbo
--- linux-2.0.37-pre3/drivers/block/paride/jumbo	1998-11-15 10:32:52.000000000 -0800
+++ linux-2.0.37-pre4/drivers/block/paride/jumbo	2003-08-15 15:04:28.000000000 -0700
@@ -53,11 +53,11 @@
 FK="-D__KERNEL__ -I ../../../include"
 FLCH=-D_LINUX_CONFIG_H
 #
-echo cc $FK $FSMP $FLCH $FPARP $FPROTO -Wall -O2 -o Jb.o -c paride.c
-cc $FK $FSMP $FLCH $FPARP $FPROTO -Wall -O2 -o Jb.o -c paride.c
+echo cc $FK $FSMP $FLCH $FPARP $FPROTO $FMODV -Wall -O2 -o Jb.o -c paride.c
+cc $FK $FSMP $FLCH $FPARP $FPROTO $FMODV -Wall -O2 -o Jb.o -c paride.c
 #
-echo cc $FK $FSMP -Wall -O2 -o Jp.o -c $PROTO.c
-cc $FK $FSMP -Wall -O2 -o Jp.o -c $PROTO.c
+echo cc $FK $FSMP $FMODV -Wall -O2 -o Jp.o -c $PROTO.c
+cc $FK $FSMP $FMODV -Wall -O2 -o Jp.o -c $PROTO.c
 #
 echo cc $FK $FSMP $FMODV -DMODULE -DPARIDE_JUMBO -Wall -O2 -o Jd.o -c $HLD.c
 cc $FK $FSMP $FMODV -DMODULE -DPARIDE_JUMBO -Wall -O2 -o Jd.o -c $HLD.c
diff -urN linux-2.0.37-pre3/drivers/block/paride/Makefile linux-2.0.37-pre4/drivers/block/paride/Makefile
--- linux-2.0.37-pre3/drivers/block/paride/Makefile	1998-11-15 10:32:52.000000000 -0800
+++ linux-2.0.37-pre4/drivers/block/paride/Makefile	2003-08-15 15:04:28.000000000 -0700
@@ -147,6 +147,15 @@
   endif
 endif
 
+
+ifeq ($(CONFIG_PARIDE_FRIQ),y)
+  LX_OBJS += friq.o
+else
+  ifeq ($(CONFIG_PARIDE_FRIQ),m)
+    M_OBJS += friq.o
+  endif
+endif
+
 ifeq ($(CONFIG_PARIDE_ON20),y)
   LX_OBJS += on20.o
 else
diff -urN linux-2.0.37-pre3/drivers/block/paride/on26.c linux-2.0.37-pre4/drivers/block/paride/on26.c
--- linux-2.0.37-pre3/drivers/block/paride/on26.c	1998-11-15 10:32:52.000000000 -0800
+++ linux-2.0.37-pre4/drivers/block/paride/on26.c	2003-08-15 15:04:28.000000000 -0700
@@ -11,10 +11,11 @@
 
         1.01    GRG 1998.05.06 init_proto, release_proto
 	1.02    GRG 1998.09.23 updates for the -E rev chip
+	1.03    GRG 1998.12.14 fix for slave drives
 
 */
 
-#define ON26_VERSION      "1.02"
+#define ON26_VERSION      "1.03"
 
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -118,9 +119,11 @@
         w2(pi->saved_r2);
 } 
 
+#define	RESET_WAIT  200
+
 static int on26_test_port( PIA *pi)  /* hard reset */
 
-{       int     i, m, d;
+{       int     i, m, d, x, y;
 
         pi->saved_r0 = r0();
         pi->saved_r2 = r2();
@@ -151,11 +154,18 @@
             
             on26_write_regr(pi,0,6,0xa0);
 
-            for (i=0;i<100;i++) {
-                if (!(on26_read_regr(pi,0,7) & 0x80)) break;
+            for (i=0;i<RESET_WAIT;i++) {
+                on26_write_regr(pi,0,6,0xa0);
+                x = on26_read_regr(pi,0,7);
+                on26_write_regr(pi,0,6,0xb0);
+                y = on26_read_regr(pi,0,7);
+                if ((x&0x80)||(y&0x80)) break;
                 udelay(100000);
             }
 
+	    if (i == RESET_WAIT) 
+		printk("on26: Device reset failed (%x,%x)\n",x,y);
+
             w0(4); P1; w0(4); P1;
         }
 
@@ -189,7 +199,7 @@
         case 1: w0(1); P1; w0(1); P2; w0(2); P1; w0(0x19); P2; w0(0); P1;
 		udelay(10);
                 for (k=0;k<count/2;k++) {
-                        w2(0x26); buf[2*k] = r0(); 
+                        w2(0x26); buf[2*k] = r0();  
 			w2(0x24); buf[2*k+1] = r0();
                 }
                 w0(2); P1; w0(9); P2;
diff -urN linux-2.0.37-pre3/drivers/block/paride/paride.c linux-2.0.37-pre4/drivers/block/paride/paride.c
--- linux-2.0.37-pre3/drivers/block/paride/paride.c	1998-07-13 13:47:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/block/paride/paride.c	2003-08-15 15:04:28.000000000 -0700
@@ -11,10 +11,12 @@
 
 	1.01	GRG 1998.05.03	Use spinlocks
 	1.02	GRG 1998.05.05  init_proto, release_proto, ktti
+	1.03    GRG 1998.08.15  eliminate compiler warning
+	1.04    GRG 1998.11.28  added support for FRIQ
 
 */
 
-#define PI_VERSION      "1.02"
+#define PI_VERSION      "1.04"
 
 #include <linux/module.h>
 #include <linux/config.h>
@@ -449,6 +451,11 @@
           pi_register(&frpw);
         };
 #endif
+#ifdef CONFIG_PARIDE_FRIQ
+        { extern struct pi_protocol friq;
+          pi_register(&friq);
+        };
+#endif 
 #ifdef CONFIG_PARIDE_FIT2
         { extern struct pi_protocol fit2;
           pi_register(&fit2);
diff -urN linux-2.0.37-pre3/drivers/block/paride/pseudo.h linux-2.0.37-pre4/drivers/block/paride/pseudo.h
--- linux-2.0.37-pre3/drivers/block/paride/pseudo.h	1998-07-13 13:47:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/block/paride/pseudo.h	2003-08-15 15:04:28.000000000 -0700
@@ -16,19 +16,21 @@
 	when either it returns true, or timeout jiffies have passed,
 	continuation() will be invoked.
 
-	If nice is true, the test will done approximately once a
+	If nice is 1, the test will done approximately once a
 	jiffy.  If nice is 0, the test will also be done whenever
-	the scheduler runs (by adding it to a task queue).
+	the scheduler runs (by adding it to a task queue).  If
+	nice is greater than 1, the test will be done once every
+	(nice-1) jiffies. 
 
 */
 
 /* Changes:
 
 	1.01	1998.05.03	Switched from cli()/sti() to spinlocks
-
+	1.02    1998.12.14      Added support for nice > 1
 */
 	
-#define PS_VERSION	"1.01"
+#define PS_VERSION	"1.02"
 
 #include <linux/sched.h>
 #include <linux/timer.h>
@@ -37,13 +39,13 @@
 static void ps_timer_int( unsigned long data);
 static void ps_tq_int( void *data);
 
-static int ps_use_tq = 1;
 static void (* ps_continuation)(void);
 static int (* ps_ready)(void);
 static int ps_then;
 static int ps_timeout;
 static int ps_timer_active = 0;
 static int ps_tq_active = 0;
+static int ps_nice = 0;
 
 /* static spinlock_t ps_spinlock = SPIN_LOCK_UNLOCKED; */
 
@@ -62,9 +64,9 @@
 	ps_ready = ready;
         ps_then = jiffies;
 	ps_timeout = jiffies + timeout;
-	ps_use_tq = !nice;
+	ps_nice = nice;
 
-        if (ps_use_tq && !ps_tq_active) {
+        if (!ps_nice && !ps_tq_active) {
 #ifdef HAVE_DISABLE_HLT
                 disable_hlt();
 #endif
@@ -74,7 +76,7 @@
 
         if (!ps_timer_active) {
 		ps_timer_active = 1;
-                ps_timer.expires = jiffies;
+                ps_timer.expires = jiffies + (ps_nice>0)?(ps_nice-1):0;
                 add_timer(&ps_timer);
         }
 
@@ -136,7 +138,7 @@
 		return;
 		}
 	ps_timer_active = 1;
-        ps_timer.expires = jiffies;
+        ps_timer.expires = jiffies + (ps_nice>0)?(ps_nice-1):0;
         add_timer(&ps_timer);
         spin_unlock_irqrestore(&ps_spinlock,flags);
 }
diff -urN linux-2.0.37-pre3/drivers/block/paride/pt.c linux-2.0.37-pre4/drivers/block/paride/pt.c
--- linux-2.0.37-pre3/drivers/block/paride/pt.c	1998-11-15 10:32:52.000000000 -0800
+++ linux-2.0.37-pre4/drivers/block/paride/pt.c	2003-08-15 15:04:28.000000000 -0700
@@ -464,7 +464,7 @@
 
 {	int	k, e, s;
 
-	k = 0;
+	k = 0; e = 0; s = 0;
 	while (k < tmo) {
 		pt_sleep(pause);
 		k++;
diff -urN linux-2.0.37-pre3/drivers/block/proc_array.c linux-2.0.37-pre4/drivers/block/proc_array.c
--- linux-2.0.37-pre3/drivers/block/proc_array.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.37-pre4/drivers/block/proc_array.c	2003-08-15 15:04:28.000000000 -0700
@@ -0,0 +1,119 @@
+/*
+ *  Taken from linux/fs/proc/net.c
+ *
+ *  Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ *  gjh 3/'93 heim@peanuts.informatik.uni-tuebingen.de (Gerald J. Heim)
+ *            most of this file is stolen from base.c
+ *            it works, but you shouldn't use it as a guideline
+ *            for new proc-fs entries. once i'll make it better.
+ * fvk 3/'93  waltje@uwalt.nl.mugnet.org (Fred N. van Kempen)
+ *	      cleaned up the whole thing, moved "net" specific code to
+ *	      the NET kernel layer (where it belonged in the first place).
+ * Michael K. Johnson (johnsonm@stolaf.edu) 3/93
+ *            Added support from my previous inet.c.  Cleaned things up
+ *            quite a bit, modularized the code.
+ * fvk 4/'93  waltje@uwalt.nl.mugnet.org (Fred N. van Kempen)
+ *	      Renamed "route_get_info()" to "rt_get_info()" for consistency.
+ * Alan Cox (gw4pts@gw4pts.ampr.org) 4/94
+ *	      Dusted off the code and added IPX. Fixed the 4K limit.
+ * Erik Schoenfelder (schoenfr@ibr.cs.tu-bs.de)
+ *	      /proc/net/snmp.
+ * Alan Cox (gw4pts@gw4pts.ampr.org) 1/95
+ *	      Added Appletalk slots
+ *
+ *  proc diskarray directory handling functions
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+
+#include <asm/segment.h>
+
+#define PROC_BLOCK_SIZE	(3*1024)		/* 4K page size but our output routines use some slack for overruns */
+
+static int proc_readdiskarray(struct inode * inode, struct file * file,
+			char * buf, int count)
+{
+	char * page;
+	int bytes=count;
+	int copied=0;
+	char *start;
+	struct proc_dir_entry * dp;
+
+	if (count < 0)
+		return -EINVAL;
+	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+		return -ENOMEM;
+
+	while (bytes>0)
+	{
+		int length, thistime=bytes;
+		if (bytes > PROC_BLOCK_SIZE)
+			thistime=PROC_BLOCK_SIZE;
+
+		length = dp->get_info(page, &start,
+				      file->f_pos,
+				      thistime, (int)dp);
+
+		/*
+ 		 *	We have been given a non page aligned block of
+		 *	the data we asked for + a bit. We have been given
+ 		 *	the start pointer and we know the length.. 
+		 */
+
+		if (length <= 0)
+			break;
+		/*
+ 		 *	Copy the bytes
+		 */
+		memcpy_tofs(buf+copied, start, length);
+		file->f_pos += length;	/* Move down the file */
+		bytes  -= length;
+		copied += length;
+		if (length<thistime)
+			break;	/* End of file */
+	}
+	free_page((unsigned long) page);
+	return copied;
+}
+
+static struct file_operations proc_diskarray_operations = {
+	NULL,			/* lseek - default */
+	proc_readdiskarray,		/* read - bad */
+	NULL,			/* write - bad */
+	NULL,			/* readdir */
+	NULL,			/* select - default */
+	NULL,			/* ioctl - default */
+	NULL,			/* mmap */
+	NULL,			/* no special open code */
+	NULL,			/* no special release code */
+	NULL			/* can't fsync */
+};
+
+/*
+ * proc directories can do almost nothing..
+ */
+struct inode_operations proc_diskarray_inode_operations = {
+	&proc_diskarray_operations,	/* default diskarray file-ops */
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL			/* permission */
+};
diff -urN linux-2.0.37-pre3/drivers/block/README.smart2 linux-2.0.37-pre4/drivers/block/README.smart2
--- linux-2.0.37-pre3/drivers/block/README.smart2	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.37-pre4/drivers/block/README.smart2	2003-08-15 15:04:28.000000000 -0700
@@ -0,0 +1,71 @@
+This driver is for Compaq's SMART2 Intellegent Disk Array Controllers.
+
+WARNING:
+--------
+
+This is still development code.  It seems to work fine for me, but I haven't
+done any real hardcore testing against this driver.  Also, things are likely
+to change, such as the major number used by the device driver as well as the
+names of the /dev entries.
+
+Installing:
+-----------
+
+You need to build a new kernel to use this device, even if you want to
+use a loadable module.  This driver requires Leonard N. Zubkoff's excellent
+patches to ll_rw_blk.c (to controll the number of scatter/gather elements
+sent to lower disk drivers).  Visit http://www.dandelion.com/Linux/DAC960.html
+to get his patches.
+
+Apply the patch to a 2.0.36 kernel after applying Leonard's patch:
+
+# cd linux
+# patch -p1 <DAC960.patch
+# patch -p1 <smart2.patch
+
+Then build a new kernel and turn on Compaq SMART2 Disk Array support.
+Create device nodes for the diskarray device:
+
+# mkdev.ida [ctlrs]
+
+Where ctlrs is the number of controllers you have (defaults to 1 if not
+specified).
+
+Booting:
+--------
+
+You'll need to use a modified lilo if you want to boot from a disk array.
+Its simply a version of lilo with some code added to tell it how to
+understand Compaq diskarray devices.
+
+Device Naming:
+--------------
+
+You need some entries in /dev for the ida device.  The mkdev.ida script
+can make device nodes for you automatically.  Currently the device setup
+is as follows:
+
+Major numbers:
+	72	ida0
+	73	ida1
+	74	ida2
+	etc...
+
+Minor numbers:
+        b7 b6 b5 b4 b3 b2 b1 b0
+        |----+----| |----+----|
+             |           |
+             |           +-------- Partition ID (0=wholedev, 1-15 partition)
+             |
+             +-------------------- Logical Volume number
+
+The suggested device naming scheme is:
+/dev/ida/c0d0		Controller 0, disk 0, whole device
+/dev/ida/c0d0p1		Controller 0, disk 0, partition 1
+/dev/ida/c0d0p2		Controller 0, disk 0, partition 2
+/dev/ida/c0d0p3		Controller 0, disk 0, partition 3
+
+/dev/ida/c1d1		Controller 1, disk 1, whole device
+/dev/ida/c1d1p1		Controller 1, disk 1, partition 1
+/dev/ida/c1d1p2		Controller 1, disk 1, partition 2
+/dev/ida/c1d1p3		Controller 1, disk 1, partition 3
diff -urN linux-2.0.37-pre3/drivers/block/TODO.smart2 linux-2.0.37-pre4/drivers/block/TODO.smart2
--- linux-2.0.37-pre3/drivers/block/TODO.smart2	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.37-pre4/drivers/block/TODO.smart2	2003-08-15 15:04:28.000000000 -0700
@@ -0,0 +1,20 @@
+Passthrough ioctl (needs testing)
+
+Missing #defines for error codes and bit definitions in arraycmd.h
+Missing structures for health and wellness stuff in arraycmd.h
+	
+Online Array config utility for userspace. 
+
+Array health monitor for userspace.  Perhaps add functionality to use
+the Event Notifier to send health events to a userspace daemon.
+
+Portability:  This driver probably doesn't work on Compaq's Alpha hardware.
+
+Performance, Performance, Performance:  There just have to be some bottlenecks
+in this driver.  I'd like to get some more profiling numbers on things, like
+how often we totally fill the controller's queue, how much stuff sits out on
+the completetion queue and timings on some critical sections of code (the
+intr. handler, the request function, cmd_alloc, etc).  The end result being
+that I'm absolutely positive that when the kernel has IO for me,  I am not
+letting the controller idle at all.
+
diff -urN linux-2.0.37-pre3/drivers/block/triton.c linux-2.0.37-pre4/drivers/block/triton.c
--- linux-2.0.37-pre3/drivers/block/triton.c	1998-07-13 13:47:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/block/triton.c	2003-08-15 15:04:28.000000000 -0700
@@ -1,107 +1,18 @@
 /*
  *  linux/drivers/block/triton.c	Version 1.13  Aug 12, 1996
+ *					Version 1.13a June 1998 - new chipsets
+ *					Version 1.13b July 1998 - DMA blacklist
  *
  *  Copyright (c) 1995-1996  Mark Lord
  *  May be copied or modified under the terms of the GNU General Public License
  */
 
 /*
- * This module provides support for the Bus Master IDE DMA function
- * of the Intel PCI Triton I/II chipsets (i82371FB or i82371SB).
- *
- * Pretty much the same code will work for the OPTi "Viper" chipset.
- * Look for DMA support for this in linux kernel 2.1.xx, when it appears.
- *
- * DMA is currently supported only for hard disk drives (not cdroms).
- *
- * Support for cdroms will likely be added at a later date,
- * after broader experience has been obtained with hard disks.
- *
- * Up to four drives may be enabled for DMA, and the Triton chipset will
- * (hopefully) arbitrate the PCI bus among them.  Note that the i82371 chip
- * provides a single "line buffer" for the BM IDE function, so performance of
- * multiple (two) drives doing DMA simultaneously will suffer somewhat,
- * as they contest for that resource bottleneck.  This is handled transparently
- * inside the i82371 chip.
- *
- * By default, DMA support is prepared for use, but is currently enabled only
- * for drives which support multi-word DMA mode2 (mword2), or which are
- * recognized as "good" (see table below).  Drives with only mode0 or mode1
- * (single or multi) DMA should also work with this chipset/driver (eg. MC2112A)
- * but are not enabled by default.  Use "hdparm -i" to view modes supported
- * by a given drive.
- *
- * The hdparm-2.4 (or later) utility can be used for manually enabling/disabling
- * DMA support, but must be (re-)compiled against this kernel version or later.
- *
- * To enable DMA, use "hdparm -d1 /dev/hd?" on a per-drive basis after booting.
- * If problems arise, ide.c will disable DMA operation after a few retries.
- * This error recovery mechanism works and has been extremely well exercised.
- *
- * IDE drives, depending on their vintage, may support several different modes
- * of DMA operation.  The boot-time modes are indicated with a "*" in
- * the "hdparm -i" listing, and can be changed with *knowledgeable* use of
- * the "hdparm -X" feature.  There is seldom a need to do this, as drives
- * normally power-up with their "best" PIO/DMA modes enabled.
- *
- * Testing was done with an ASUS P55TP4XE/100 system and the following drives:
- *
- *   Quantum Fireball 1080A (1Gig w/83kB buffer), DMA mode2, PIO mode4.
- *	- DMA mode2 works well (7.4MB/sec), despite the tiny on-drive buffer.
- *	- This drive also does PIO mode4, at about the same speed as DMA mode2.
- *	  An awesome drive for the price!
- *
- *   Fujitsu M1606TA (1Gig w/256kB buffer), DMA mode2, PIO mode4.
- *	- DMA mode2 gives horrible performance (1.6MB/sec), despite the good
- *	  size of the on-drive buffer and a boasted 10ms average access time.
- *	- PIO mode4 was better, but peaked at a mere 4.5MB/sec.
- *
- *   Micropolis MC2112A (1Gig w/508kB buffer), drive pre-dates EIDE and ATA2.
- *	- DMA works fine (2.2MB/sec), probably due to the large on-drive buffer.
- *	- This older drive can also be tweaked for fastPIO (3.7MB/sec) by using
- *	  maximum clock settings (5,4) and setting all flags except prefetch.
- *
- *   Western Digital AC31000H (1Gig w/128kB buffer), DMA mode1, PIO mode3.
- *	- DMA does not work reliably.  The drive appears to be somewhat tardy
- *	  in deasserting DMARQ at the end of a sector.  This is evident in
- *	  the observation that WRITEs work most of the time, depending on
- *	  cache-buffer occupancy, but multi-sector reads seldom work.
- *
- * Testing was done with a Gigabyte GA-586 ATE system and the following drive:
- * (Uwe Bonnes - bon@elektron.ikp.physik.th-darmstadt.de)
- *
- *   Western Digital AC31600H (1.6Gig w/128kB buffer), DMA mode2, PIO mode4.
- *	- much better than its 1Gig cousin, this drive is reported to work
- *	  very well with DMA (7.3MB/sec).
- *
- * Other drives:
- *
- *   Maxtor 7540AV (515Meg w/32kB buffer), DMA modes mword0/sword2, PIO mode3.
- *	- a budget drive, with budget performance, around 3MB/sec.
- *
- *   Western Digital AC2850F (814Meg w/64kB buffer), DMA mode1, PIO mode3.
- *	- another "caviar" drive, similar to the AC31000, except that this one
- *	  worked with DMA in at least one system.  Throughput is about 3.8MB/sec
- *	  for both DMA and PIO.
- *
- *   Conner CFS850A (812Meg w/64kB buffer), DMA mode2, PIO mode4.
- *	- like most Conner models, this drive proves that even a fast interface
- *	  cannot improve slow media.  Both DMA and PIO peak around 3.5MB/sec.
- *
- *   Maxtor 71260AT (1204Meg w/256kB buffer), DMA mword0/sword2, PIO mode3.
- *	- works with DMA, on some systems (but not always on others, eg. Dell),
- *	giving 3-4MB/sec performance, about the same as mode3.
- *
- * If you have any drive models to add, email your results to:  mlord@pobox.com
- * Keep an eye on /var/adm/messages for "DMA disabled" messages.
- *
- * Some people have reported trouble with Intel Zappa motherboards.
- * This can be fixed by upgrading the AMI BIOS to version 1.00.04.BS0,
- * available from ftp://ftp.intel.com/pub/bios/10004bs0.exe
- * (thanks to Glen Morrell <glen@spin.Stanford.edu> for researching this).
- *
- * And, yes, Intel Zappa boards really *do* use the Triton IDE ports.
+ * This module provides support for Bus Master IDE DMA functions in various
+ * motherboard chipsets and PCI controller cards.
+ * Please check /Documentation/ide.txt and /Documentation/udma.txt for details.
  */
+
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -120,6 +31,13 @@
 #include "ide.h"
 
 #undef DISPLAY_TRITON_TIMINGS	/* define this to display timings */
+#undef DISPLAY_APOLLO_TIMINGS	/* define this for extensive debugging information */
+
+#if defined(CONFIG_PROC_FS) && defined(DISPLAY_APOLLO_TIMINGS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#include <linux/via_ide_dma.h>
+#endif
 
 /*
  * good_dma_drives() lists the model names (from "hdparm -i")
@@ -132,6 +50,27 @@
 				 NULL};
 
 /*
+ * bad_dma_drives() lists the model names (from "hdparm -i")
+ * of drives which supposedly support (U)DMA but which are
+ * known to corrupt data with this interface under Linux.
+ *
+ * Note: the list was generated by statistical analysis of problem
+ * reports. It's not clear if there are problems with the drives,
+ * or with some combination of drive/controller or what. 
+ *
+ * You can forcibly override this if you wish. This is the kernel
+ * 'Tread carefully' list.
+ *
+ * Finally see http://www.wdc.com/quality/err-rec.html if you have
+ * one of the listed drives. 
+ */
+const char *bad_dma_drives[] = {"WDC AC11000H",
+				"WDC AC22100H",
+				"WDC AC32500H",
+				"WDC AC33100H",
+				 NULL};
+
+/*
  * Our Physical Region Descriptor (PRD) table should be large enough
  * to handle the biggest I/O request we are likely to see.  Since requests
  * can have no more than 256 sectors, and since the typical blocksize is
@@ -150,6 +89,7 @@
 #define PRD_BYTES	8
 #define PRD_ENTRIES	(PAGE_SIZE / (2 * PRD_BYTES))
 #define DEFAULT_BMIBA	0xe800	/* in case BIOS did not init it */
+#define DEFAULT_BMCRBA  0xcc00  /* VIA's default value */
 
 /*
  * dma_intr() is the handler for disk read/write DMA interrupts
@@ -161,8 +101,8 @@
 	struct request *rq = HWGROUP(drive)->rq;
 	unsigned short dma_base = HWIF(drive)->dma_base;
 
-	dma_stat = inb(dma_base+2);		/* get DMA status */
 	outb(inb(dma_base)&~1, dma_base);	/* stop DMA operation */
+	dma_stat = inb(dma_base+2);		/* get DMA status */
 	stat = GET_STAT();			/* get drive status */
 	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
 		if ((dma_stat & 7) == 4) {	/* verify good DMA status */
@@ -244,23 +184,37 @@
 	return 1;	/* let the PIO routines handle this weirdness */
 }
 
+/*
+ * We will only enable drives with multi-word (mode2) (U)DMA capabilities,
+ * and ignore the very rare cases of drives that can only do single-word
+ * (modes 0 & 1) (U)DMA transfers. We also discard "blacklisted" hard disks.
+ */
 static int config_drive_for_dma (ide_drive_t *drive)
 {
 	const char **list;
 	struct hd_driveid *id = drive->id;
 
 	if (id && (id->capability & 1)) {
-		/* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
+		/* Consult the list of known "bad" drives */
+		list = bad_dma_drives;
+		while (*list) {
+			if (!strcmp(*list++,id->model)) {
+				drive->using_dma = 0;   /* no DMA */
+				printk("ide: Disabling DMA modes on %s drive (%s).\n", drive->name, id->model);
+				return 1;	/* DMA disabled */
+			}
+		}
+		/* Enable DMA on any drive that has mode 2 UltraDMA enabled */
 		if (id->field_valid & 4)	/* UltraDMA */
-			if  ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
+			if  ((id->dma_ultra & 0x404) == 0x404) {
 				drive->using_dma = 1;
-				return 0;	/* dma enabled */
+				return 0;	/* DMA enabled */
 			}
-		/* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
+		/* Enable DMA on any drive that has mode2 DMA enabled */
 		if (id->field_valid & 2)	/* regular DMA */
-			if  ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404) {
+			if  ((id->dma_mword & 0x404) == 0x404) {
 				drive->using_dma = 1;
-				return 0;	/* dma enabled */
+				return 0;	/* DMA enabled */
 			}
 		/* Consult the list of known "good" drives */
 		list = good_dma_drives;
@@ -387,22 +341,135 @@
 }
 
 /*
+ *  Set VIA Chipset Timings for (U)DMA modes enabled.
+ */
+static int set_via_timings (byte bus, byte fn, byte post, byte flush)
+{
+	byte via_config = 0;
+	int rc = 0;
+
+	/* setting IDE read prefetch buffer and IDE post write buffer */
+	if ((rc = pcibios_read_config_byte(bus, fn, 0x41, &via_config)))
+		return (1);
+	if ((rc = pcibios_write_config_byte(bus, fn, 0x41, via_config | post)))
+		return (1);
+
+	/* setting Channel read and End-of-sector FIFO flush: */
+	if ((rc = pcibios_read_config_byte(bus, fn, 0x46, &via_config)))
+		return (1);
+	if ((rc = pcibios_write_config_byte(bus, fn, 0x46, via_config | flush)))
+		return (1);
+
+	return (0);
+}
+
+/*
  * ide_init_triton() prepares the IDE driver for DMA operation.
  * This routine is called once, from ide.c during driver initialization,
- * for each triton chipset which is found (unlikely to be more than one).
+ * for each BM-DMA chipset which is found (rarely more than one).
  */
 void ide_init_triton (byte bus, byte fn)
 {
 	int rc = 0, h;
 	int dma_enabled = 0;
-	unsigned short pcicmd;
-	unsigned int bmiba, timings;
+	unsigned short io[6], count = 0, step_count = 0;
+	unsigned short pcicmd, vendor, device, class;
+	unsigned int bmiba, timings, reg, tmp;
+	unsigned int addressbios = 0;
+
+#ifdef DISPLAY_APOLLO_TIMINGS
+	bmide_bus = bus;
+	bmide_fn = fn;
+#endif /* DISPLAY_APOLLO_TIMINGS */
+
+/*
+ *  We pick up the vendor, device, and class info for selecting the correct
+ *  controller that is supported.  Since we can access this routine more than
+ *  once with the use of onboard and off-board EIDE controllers, a method
+ *  of determining "who is who for what" is needed.
+ */
+
+	pcibios_read_config_word (bus, fn, PCI_VENDOR_ID, &vendor);
+	pcibios_read_config_word (bus, fn, PCI_DEVICE_ID, &device);
+	pcibios_read_config_word (bus, fn, PCI_CLASS_DEVICE, &class);
+
+	switch(vendor) {
+		case PCI_VENDOR_ID_INTEL:
+                   printk("ide: Intel 82371 (single FIFO) DMA Bus Mastering IDE ");
+                   break;
+		case PCI_VENDOR_ID_SI:
+			printk("ide: SiS 5513 (dual FIFO) DMA Bus Mastering IDE ");
+			break;
+                case PCI_VENDOR_ID_VIA:
+                   printk("ide: VIA VT82C586B (split FIFO) UDMA Bus Mastering IDE ");
+                   break;
+		case PCI_VENDOR_ID_PROMISE:
+			/*	PCI_CLASS_STORAGE_RAID == class	*/
+			/*
+			 *  I have been able to make my Promise Ultra33 UDMA card change class.
+			 *  It has reported as both PCI_CLASS_STORAGE_RAID and PCI_CLASS_STORAGE_IDE.
+			 *  Since the PCI_CLASS_STORAGE_RAID mode should automatically mirror the
+			 *  two halves of the PCI_CONFIG register data, but sometimes it forgets.
+			 *  Thus we guarantee that they are identical, with a quick check and
+			 *  correction if needed.
+			 *  PDC20246 (primary) PDC20247 (secondary) IDE hwif's.
+			 *
+			 *  Note that Promise "stories,fibs,..." about this device not being
+			 *  capable of ATAPI and AT devices.
+			 */
+			if (PCI_CLASS_STORAGE_RAID == class) {
+				unsigned char irq1 = 0, irq2 = 0;
+				pcibios_read_config_byte (bus, fn, PCI_INTERRUPT_LINE, &irq1);
+				pcibios_read_config_byte (bus, fn, (PCI_INTERRUPT_LINE)|0x80, &irq2);
+				if (irq1 != irq2) {
+					pcibios_write_config_byte(bus, fn, (PCI_INTERRUPT_LINE)|0x80, irq1);
+				}
+			}
+		case PCI_VENDOR_ID_ARTOP:
+			/*	PCI_CLASS_STORAGE_SCSI == class	*/
+			/*
+			 *  I have found that by stroking rom_enable_bit on both the AEC6210U/UF and
+			 *  PDC20246 controller cards, the features desired are almost guaranteed
+			 *  to be enabled and compatible.  This ROM may not be registered in the
+			 *  config data, but it can be turned on.  Registration failure has only
+			 *  been observed if and only if Linux sets up the pci_io_address in the
+			 *  0x6000 range.  If they are setup in the 0xef00 range it is reported.
+			 *  WHY??? got me.........
+			 */
+			printk("ide: %s UDMA Bus Mastering ",
+				(vendor == PCI_VENDOR_ID_ARTOP) ? "AEC6210" : "PDC20246");
+			pcibios_read_config_dword(bus, fn, PCI_ROM_ADDRESS, &addressbios);
+			if (addressbios) {
+				pcibios_write_config_byte(bus, fn, PCI_ROM_ADDRESS, addressbios | PCI_ROM_ADDRESS_ENABLE);
+				printk("with ROM enabled at 0x%08x", addressbios);
+			}
+			/*
+			 *  This was stripped out of 2.1.XXX kernel code and parts from a patch called
+			 *  promise_update.  This finds the PCI_BASE_ADDRESS spaces and makes them
+			 *  available for configuration later.
+			 *  PCI_BASE_ADDRESS_0  hwif0->io_base
+			 *  PCI_BASE_ADDRESS_1  hwif0->ctl_port
+			 *  PCI_BASE_ADDRESS_2  hwif1->io_base
+			 *  PCI_BASE_ADDRESS_3  hwif1->ctl_port
+			 *  PCI_BASE_ADDRESS_4  bmiba
+			 */
+			memset(io, 0, 6 * sizeof(unsigned short));
+			for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) {
+				pcibios_read_config_dword(bus, fn, reg, &tmp);
+				if (tmp & PCI_BASE_ADDRESS_SPACE_IO)
+					io[count++] = tmp & PCI_BASE_ADDRESS_IO_MASK;
+			}
+			break;
+		default:
+			return;
+	}
+
+	printk("\n    Controller on PCI bus %d function %d\n", bus, fn);
 
-	printk("ide: i82371 PIIX (Triton) on PCI bus %d function %d\n", bus, fn);
 	/*
 	 * See if IDE and BM-DMA features are enabled:
 	 */
-	if ((rc = pcibios_read_config_word(bus, fn, 0x04, &pcicmd)))
+	if ((rc = pcibios_read_config_word(bus, fn, PCI_COMMAND, &pcicmd)))
 		goto quit;
 	if ((pcicmd & 1) == 0)  {
 		printk("ide: ports are not enabled (BIOS)\n");
@@ -416,21 +483,21 @@
 		 */
 		int try_again = 1;
 		do {
-			if ((rc = pcibios_read_config_dword(bus, fn, 0x20, &bmiba)))
+			if ((rc = pcibios_read_config_dword(bus, fn, PCI_BASE_ADDRESS_4, &bmiba)))
 				goto quit;
 			bmiba &= 0xfff0;	/* extract port base address */
 			if (bmiba) {
 				dma_enabled = 1;
 				break;
 			} else {
-				printk("ide: BM-DMA base register is invalid (0x%04x, PnP BIOS problem)\n", bmiba);
-				if (inb(DEFAULT_BMIBA) != 0xff || !try_again)
+                                printk("ide: BM-DMA base register is invalid (0x%04x, PnP BIOS problem)\n", bmiba);
+                                if (inb(((vendor == PCI_VENDOR_ID_VIA) ? DEFAULT_BMCRBA : DEFAULT_BMIBA)) != 0xff || !try_again)
 					break;
-				printk("ide: setting BM-DMA base register to 0x%04x\n", DEFAULT_BMIBA);
-				if ((rc = pcibios_write_config_word(bus, fn, 0x04, pcicmd&~1)))
+				printk("ide: setting BM-DMA base register to 0x%04x\n", ((vendor == PCI_VENDOR_ID_VIA) ? DEFAULT_BMCRBA : DEFAULT_BMIBA));
+				if ((rc = pcibios_write_config_word(bus, fn, PCI_COMMAND, pcicmd&~1)))
 					goto quit;
-				rc = pcibios_write_config_dword(bus, fn, 0x20, DEFAULT_BMIBA|1);
-				if (pcibios_write_config_word(bus, fn, 0x04, pcicmd|5) || rc)
+				rc = pcibios_write_config_dword(bus, fn, 0x20, ((vendor == PCI_VENDOR_ID_VIA) ? DEFAULT_BMCRBA : DEFAULT_BMIBA)|1);
+				if (pcibios_write_config_word(bus, fn, PCI_COMMAND, pcicmd|5) || rc)
 					goto quit;
 			}
 		} while (try_again--);
@@ -439,89 +506,218 @@
 	/*
 	 * See if ide port(s) are enabled
 	 */
-	if ((rc = pcibios_read_config_dword(bus, fn, 0x40, &timings)))
-		goto quit;
-	if (!(timings & 0x80008000)) {
-		printk("ide: neither port is enabled\n");
+	if ((rc = pcibios_read_config_dword(bus, fn,
+		(vendor == PCI_VENDOR_ID_PROMISE) ? 0x50 : 
+		(vendor == PCI_VENDOR_ID_ARTOP) ? 0x54 :
+		0x40, &timings)))
 		goto quit;
-	}
+	/*
+	 * We do a vendor check since the Ultra33 and AEC6210
+	 * holds their timings in a different location.
+	 */
+	printk("ide: timings == %08x\n", timings);
+
+	/*
+	 *  The switch preserves some stuff that was original.
+	 */
+	switch(vendor) {
+		case PCI_VENDOR_ID_INTEL:
+			if (!(timings & 0x80008000)) {
+				printk("ide: INTEL: neither port is enabled\n");
+				goto quit;
+			}
+			break;
+		case PCI_VENDOR_ID_VIA:
+			if(!(timings & 0x03)) {
+				printk("ide: VIA: neither port is enabled\n");
+				goto quit;
+			}
+			break;
+		case PCI_VENDOR_ID_SI:
+		case PCI_VENDOR_ID_PROMISE:
+		case PCI_VENDOR_ID_ARTOP:
+                default:
+                        break;
+        }
 
 	/*
 	 * Save the dma_base port addr for each interface
 	 */
 	for (h = 0; h < MAX_HWIFS; ++h) {
+		ide_hwif_t *hwif = &ide_hwifs[h];
+
+		/*
+		 *  This prevents the first contoller from accidentally
+		 *  initalizing the hwif's that it does not use and block
+		 *  an off-board ide-pci from getting in the game.
+		 */
+		if (step_count >= 2) {
+			goto quit;
+		}
+#ifdef CONFIG_BLK_DEV_OFFBOARD
+		/*
+		 *  This is a forced override for the onboard ide controller
+		 *  to be enabled, if one chooses to have an offboard ide-pci
+		 *  card as the primary booting device.  This beasty is
+		 *  for offboard UDMA upgrades with hard disks, but saving
+		 *  the onboard DMA2 controllers for CDROMS, TAPES, ZIPS, etc...
+		 */
+		if ((vendor == PCI_VENDOR_ID_INTEL) ||
+		    (vendor == PCI_VENDOR_ID_SI) ||
+		    (vendor == PCI_VENDOR_ID_VIA)) {
+			if (h == 2) {
+				hwif->io_base = 0x1f0;
+				hwif->ctl_port = 0x3f6;
+				hwif->irq = 14;
+				hwif->noprobe = 0;
+			}
+			if (h == 3) {
+				hwif->io_base = 0x170;
+				hwif->ctl_port = 0x376;
+				hwif->irq = 15;
+				hwif->noprobe = 0;
+			}
+		}
+#endif /* CONFIG_BLK_DEV_OFFBOARD */
+		/*
+		 *  If the chipset is listed as "ide_unknown", lets get a
+		 *  hwif while they last.  This does the first check on
+		 *  the current availability of the ide_hwifs[h] in question.
+		 */
+		if (hwif->chipset != ide_unknown) {
+			continue;
+		} else if (vendor == PCI_VENDOR_ID_INTEL) {
+			unsigned short time;
 #ifdef DISPLAY_TRITON_TIMINGS
-		byte s_clks, r_clks;
-		unsigned short devid;
+			byte s_clks, r_clks;
+			unsigned short devid;
 #endif /* DISPLAY_TRITON_TIMINGS */
-		ide_hwif_t *hwif = &ide_hwifs[h];
-		unsigned short time;
-		if (hwif->io_base == 0x1f0) {
-			time = timings & 0xffff;
-			if ((time & 0x8000) == 0)	/* interface enabled? */
-				continue;
-			hwif->chipset = ide_triton;
-			if (dma_enabled)
-				init_triton_dma(hwif, bmiba);
-		} else if (hwif->io_base == 0x170) {
-			time = timings >> 16;
-			if ((time & 0x8000) == 0)	/* interface enabled? */
+			if (hwif->io_base == 0x1f0) {
+				time = timings & 0xffff;
+				if ((time & 0x8000) == 0)	/* interface enabled? */
+					continue;
+				hwif->chipset = ide_triton;
+				if (dma_enabled)
+					init_triton_dma(hwif, bmiba);
+				step_count++;
+			} else if (hwif->io_base == 0x170) {
+				time = timings >> 16;
+				if ((time & 0x8000) == 0)	/* interface enabled? */
+					continue;
+				hwif->chipset = ide_triton;
+				if (dma_enabled)
+					init_triton_dma(hwif, bmiba + 8);
+				step_count++;
+			} else {
 				continue;
-			hwif->chipset = ide_triton;
-			if (dma_enabled)
-				init_triton_dma(hwif, bmiba + 8);
-		} else
-			continue;
+			}
 #ifdef DISPLAY_TRITON_TIMINGS
-		s_clks = ((~time >> 12) & 3) + 2;
-		r_clks = ((~time >>  8) & 3) + 1;
-		printk("    %s timing: (0x%04x) sample_CLKs=%d, recovery_CLKs=%d\n",
-		 hwif->name, time, s_clks, r_clks);
-		if ((time & 0x40) && !pcibios_read_config_word(bus, fn, 0x02, &devid)
-		 && devid == PCI_DEVICE_ID_INTEL_82371SB_1)
-		{
-			byte stime;
-			if (pcibios_read_config_byte(bus, fn, 0x44, &stime)) {
-				if (hwif->io_base == 0x1f0) {
-					s_clks = ~stime >> 6;
-					r_clks = ~stime >> 4;
+			s_clks = ((~time >> 12) & 3) + 2;
+			r_clks = ((~time >>  8) & 3) + 1;
+			printk("    %s timing: (0x%04x) sample_CLKs=%d, recovery_CLKs=%d\n",
+				hwif->name, time, s_clks, r_clks);
+			if ((time & 0x40) && !pcibios_read_config_word(bus, fn, PCI_DEVICE_ID, &devid)
+				&& devid == PCI_DEVICE_ID_INTEL_82371SB_1) {
+				byte stime;
+				if (pcibios_read_config_byte(bus, fn, 0x44, &stime)) {
+					if (hwif->io_base == 0x1f0) {
+						s_clks = ~stime >> 6;
+						r_clks = ~stime >> 4;
+					} else {
+						s_clks = ~stime >> 2;
+						r_clks = ~stime;
+					}
+					s_clks = (s_clks & 3) + 2;
+					r_clks = (r_clks & 3) + 1;
+					printk("                   slave: sample_CLKs=%d, recovery_CLKs=%d\n",
+						s_clks, r_clks);
+				}
+			}
+			print_triton_drive_flags (0, time & 0xf);
+			print_triton_drive_flags (1, (time >> 4) & 0xf);
+#endif /* DISPLAY_TRITON_TIMINGS */
+		} else if (vendor == PCI_VENDOR_ID_SI) {
+			if (hwif->io_base == 0x1f0) {
+				hwif->chipset = ide_triton;
+				if (dma_enabled)
+					init_triton_dma(hwif, bmiba);
+				step_count++;
+			} else if (hwif->io_base == 0x170) {
+				hwif->chipset = ide_triton;
+				if (dma_enabled)
+					init_triton_dma(hwif, bmiba + 8);
+				step_count++;
+			} else {
+				continue;
+			}
+		} else if(vendor == PCI_VENDOR_ID_VIA) {
+			if (hwif->io_base == 0x1f0) {
+				if((timings & 0x02) == 0)
+					continue;
+				hwif->chipset = ide_triton;
+				if (dma_enabled)
+					init_triton_dma(hwif, bmiba);
+				if (set_via_timings(bus, fn, 0xc0, 0xa0))
+					goto quit;
+#ifdef DISPLAY_APOLLO_TIMINGS
+				proc_register_dynamic(&proc_root, &via_proc_entry);
+#endif /* DISPLAY_APOLLO_TIMINGS */
+				step_count++;
+			} else if (hwif->io_base == 0x170) {
+				if((timings & 0x01) == 0)
+					continue;
+				hwif->chipset = ide_triton;
+				if (dma_enabled)
+					init_triton_dma(hwif, bmiba + 8);
+				if (set_via_timings(bus, fn, 0x30, 0x50))
+					goto quit;
+				step_count++;
+			} else {
+				continue;
+			}
+		} else if ((vendor == PCI_VENDOR_ID_PROMISE) ||
+			   (vendor == PCI_VENDOR_ID_ARTOP)) {
+	/*
+	 *  This silly tmp = h routine allows an off-board ide-pci card to
+	 *  be booted as primary hwifgroup, provided that the onboard
+	 *  controllers are disabled.  If they are active, then we wait our
+	 *  turn for hwif assignment.
+	 */
+			unsigned char irq = 0;
+			pcibios_read_config_byte (bus, fn, PCI_INTERRUPT_LINE, &irq);
+			if ((h == 0) || (h == 1)) {
+				tmp = h * 2;
+			} else {
+				tmp = (h - 2) * 2;
+			}
+			hwif->io_base = io[tmp];
+			hwif->ctl_port = io[tmp + 1] + 2;
+			hwif->irq = irq;
+			hwif->noprobe = 0;
+
+			if (vendor == PCI_VENDOR_ID_ARTOP) {
+				hwif->serialized = 1;
+			}
+
+			if (dma_enabled) {
+				if (!check_region(bmiba, 8)) {
+					hwif->chipset = ide_udma;
+					init_triton_dma(hwif, bmiba);
+					step_count++;
+				} else if (!check_region((bmiba + 0x08), 8)) {
+					if ((vendor == PCI_VENDOR_ID_PROMISE) &&
+					    (!check_region(bmiba+16, 16))) {
+						request_region(bmiba+16, 16, "PDC20246");
+					}
+					hwif->chipset = ide_udma;
+					init_triton_dma(hwif, bmiba + 8);
+					step_count++;
 				} else {
-					s_clks = ~stime >> 2;
-					r_clks = ~stime;
+					continue;
 				}
-				s_clks = (s_clks & 3) + 2;
-				r_clks = (r_clks & 3) + 1;
-				printk("                   slave: sample_CLKs=%d, recovery_CLKs=%d\n",
-		 			s_clks, r_clks);
 			}
 		}
-		print_triton_drive_flags (0, time & 0xf);
-		print_triton_drive_flags (1, (time >> 4) & 0xf);
-#endif /* DISPLAY_TRITON_TIMINGS */
 	}
 
-quit: if (rc) printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc));
-}
-
-void ide_init_promise (byte bus, byte fn, ide_hwif_t *hwif0, ide_hwif_t *hwif1, unsigned short dma)
-{
-	int rc;
-	unsigned short pcicmd;
-	unsigned int bmiba = 0;
-
-	printk("ide: Enabling DMA for Promise Technology IDE Ultra-DMA 33 on PCI bus %d function %d, port 0x%04x\n", bus, fn, dma);
-	if ((rc = pcibios_read_config_word(bus, fn, 0x04, &pcicmd)) || (pcicmd & 1) == 0 || (pcicmd & 4) == 0)
-		goto abort;
-	if ((rc = pcibios_read_config_dword(bus, fn, 0x20, &bmiba)))
-		goto abort;
-	bmiba &= 0xfff0;	/* extract port base address */
-	if (bmiba != dma || !bmiba)
-		goto abort;
-	hwif0->chipset = ide_promise_udma;
-	hwif1->chipset = ide_promise_udma;
-	init_triton_dma(hwif0, bmiba);
-	init_triton_dma(hwif1, bmiba + 0x08);
-	return;
-abort:
-	printk(KERN_WARNING "ide: Promise/33 not configured correctly (BIOS)\n");
+	quit: if (rc) printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc));
 }
diff -urN linux-2.0.37-pre3/drivers/char/serial.c linux-2.0.37-pre4/drivers/char/serial.c
--- linux-2.0.37-pre3/drivers/char/serial.c	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/char/serial.c	2003-08-15 15:04:28.000000000 -0700
@@ -57,7 +57,7 @@
 #include <asm/bitops.h>
 
 static char *serial_name = "Serial driver";
-static char *serial_version = "4.13p";
+static char *serial_version = "4.13p1";
 
 DECLARE_TASK_QUEUE(tq_serial);
 
@@ -1806,6 +1806,26 @@
 
 
 /*
+ * rs_break() --- routine which turns the break handling on or off
+ * adapted from 2.1.124
+ */
+static void rs_break(struct async_struct * info, int break_state)
+{
+        unsigned long flags;
+        
+        if (!info->port)
+                return;
+        save_flags(flags);cli();
+        if (break_state == -1)
+                serial_out(info, UART_LCR,
+                           serial_inp(info, UART_LCR) | UART_LCR_SBC);
+        else
+                serial_out(info, UART_LCR,
+                           serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
+        restore_flags(flags);
+}
+
+/*
  * This routine sends a break character out the serial port.
  */
 static void send_break(	struct async_struct * info, int duration)
@@ -1997,6 +2017,20 @@
 	}
 	
 	switch (cmd) {
+                case TIOCSBRK:  /* Turn break on, unconditionally */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			rs_break(info,-1);
+			return 0;
+                case TIOCCBRK:  /* Turn break off, unconditionally */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			rs_break(info,0);
+			return 0;
 		case TCSBRK:	/* SVID version: non-zero arg --> no break */
 			retval = tty_check_change(tty);
 			if (retval)
diff -urN linux-2.0.37-pre3/drivers/net/epic100.c linux-2.0.37-pre4/drivers/net/epic100.c
--- linux-2.0.37-pre3/drivers/net/epic100.c	1998-11-15 10:33:03.000000000 -0800
+++ linux-2.0.37-pre4/drivers/net/epic100.c	2003-08-15 15:04:28.000000000 -0700
@@ -1,6 +1,6 @@
 /* epic100.c: A SMC 83c170 EPIC/100 Fast Ethernet driver for Linux. */
 /*
-	Written 1997-1998 by Donald Becker.
+	Written/copyright 1997-1998 by Donald Becker.
 
 	This software may be used and distributed according to the terms
 	of the GNU Public License, incorporated herein by reference.
@@ -10,15 +10,15 @@
 	SMC EtherPower II 9432 PCI adapter, and several CardBus cards.
 
 	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
-	Center of Excellence in Space Data and Information Sciences
+	USRA Center of Excellence in Space Data and Information Sciences
 	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
 
-	Support and updates available at
+	Information and updates available at
 	http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html
 */
 
 static const char *version =
-"epic100.c:v1.03 8/7/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html\n";
+"epic100.c:v1.04 8/23/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/epic100.html\n";
 
 /* A few user-configurable values. */
 
@@ -118,6 +118,7 @@
 /* The I/O extent. */
 #define EPIC_TOTAL_SIZE 0x100
 
+#define epic_debug debug
 static int epic_debug = 1;
 
 /*
@@ -155,7 +156,8 @@
 /* The rest of these values should never change. */
 
 static struct device *epic_probe1(int pci_bus, int pci_devfn,
-									 struct device *dev, int card_idx);
+								  struct device *dev, long ioaddr, int irq,
+								  int chip_id, int card_idx);
 
 enum pci_flags_bit {
 	PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
@@ -166,9 +168,11 @@
 	u16	vendor_id, device_id, device_id_mask, pci_flags;
 	int io_size, min_latency;
 	struct device *(*probe1)(int pci_bus, int pci_devfn, struct device *dev,
-							 int chip_idx);
+							 long ioaddr, int irq, int chip_idx, int fnd_cnt);
 } chip_tbl[] = {
-	{"SMSC EPIC/100", 0x10B8, 0x0005, 0x7fff,
+	{"SMSC EPIC/100 83c170", 0x10B8, 0x0005, 0x7fff,
+	 PCI_USES_IO|PCI_USES_MASTER|PCI_ADDR0, EPIC_TOTAL_SIZE, 32, epic_probe1},
+	{"SMSC EPIC/C 83c175", 0x10B8, 0x0006, 0x7fff,
 	 PCI_USES_IO|PCI_USES_MASTER|PCI_ADDR0, EPIC_TOTAL_SIZE, 32, epic_probe1},
 	{0,},
 };
@@ -276,7 +280,7 @@
 int epic100_probe(struct device *dev)
 {
 	int cards_found = 0;
-	int chip_idx;
+	int chip_idx, irq;
 	u16 pci_command, new_command;
 	unsigned char pci_bus, pci_device_fn;
 
@@ -298,6 +302,7 @@
 			continue;
 		pci_bus = pcidev->bus->number;
 		pci_device_fn = pcidev->devfn;
+		irq = pcidev->irq;
 #else
 	int pci_index;
 
@@ -305,6 +310,7 @@
 		return -ENODEV;
 
 	for (pci_index = 0; pci_index < 0xff; pci_index++) {
+		u8 pci_irq_line;
 		u16 vendor, device;
 		u32 pci_ioaddr;
 
@@ -327,8 +333,11 @@
 
 		pcibios_read_config_dword(pci_bus, pci_device_fn,
 								  PCI_BASE_ADDRESS_0, &pci_ioaddr);
+		pcibios_read_config_byte(pci_bus, pci_device_fn,
+								 PCI_INTERRUPT_LINE, &pci_irq_line);
 		/* Remove I/O space marker in bit 0. */
 		pci_ioaddr &= ~3;
+		irq = pci_irq_line;
 
 		if (check_region(pci_ioaddr, chip_tbl[chip_idx].io_size))
 			continue;
@@ -350,8 +359,8 @@
 									  PCI_COMMAND, new_command);
 		}
 
-		dev = chip_tbl[chip_idx].probe1(pci_bus, pci_device_fn,
-										dev, cards_found);
+		dev = chip_tbl[chip_idx].probe1(pci_bus, pci_device_fn, dev, pci_ioaddr,
+									   irq, chip_idx, cards_found);
 
 		/* Check the latency timer. */
 		if (dev) {
@@ -375,17 +384,12 @@
 }
 #endif  /* not CARDBUS */
 
-static struct device *epic_probe1(int bus, int devfn, struct device *dev,
-									 int card_idx)
+static struct device *epic_probe1(int pci_bus, int pci_devfn,
+								  struct device *dev, long ioaddr, int irq,
+								  int chip_idx, int card_idx)
 {
-	static int did_version = 0;			/* Already printed version info. */
 	struct epic_private *ep;
 	int i, option = 0, duplex = 0;
-	u16 chip_id;
-	u32 ioaddr;
-
-	if (epic_debug > 0  &&  did_version++ == 0)
-		printk(KERN_INFO "%s", version);
 
 	if (dev && dev->mem_start) {
 		option = dev->mem_start;
@@ -399,26 +403,10 @@
 
 	dev = init_etherdev(dev, 0);
 
-	{		/* Grrrr, badly consider interface change. */
-#if defined(PCI_SUPPORT_VER2)
-		struct pci_dev *pdev = pci_find_slot(bus, devfn);
-		ioaddr = pdev->base_address[0] & ~3;
-		dev->irq = pdev->irq;
-		chip_id = pdev->device;
-#else
-		u8 irq;
-		u32 ioaddr0;
-		pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &ioaddr0);
-		pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
-		pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &chip_id);
-		ioaddr = ioaddr0 & ~3;
-		dev->irq = irq;
-#endif
-	}
-
 	dev->base_addr = ioaddr;
-	printk(KERN_INFO "%s: SMC EPIC/100 (chip ID %4.4x) at %#3x, IRQ %d, ",
-		   dev->name, chip_id, ioaddr, dev->irq);
+	dev->irq = irq;
+	printk(KERN_INFO "%s: SMC EPIC/100 at %#lx, IRQ %d, ",
+		   dev->name, ioaddr, dev->irq);
 
 	/* Bring the chip out of low-power mode. */
 	outl(0x4200, ioaddr + GENCTL);
@@ -427,7 +415,7 @@
 
 	/* Turn on the MII transceiver. */
 	outl(0x12, ioaddr + MIICfg);
-	if (chip_id == 6)
+	if (chip_idx == 1)
 		outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
 	outl(0x0200, ioaddr + GENCTL);
 
@@ -447,7 +435,7 @@
 	}
 
 	/* We do a request_region() to register /proc/ioports info. */
-	request_region(ioaddr, EPIC_TOTAL_SIZE, "SMC EPIC/100");
+	request_region(ioaddr, EPIC_TOTAL_SIZE, dev->name);
 
 	/* The data structures must be quadword aligned. */
 	ep = kmalloc(sizeof(*ep), GFP_KERNEL | GFP_DMA);
@@ -457,9 +445,13 @@
 	ep->next_module = root_epic_dev;
 	root_epic_dev = dev;
 
-	ep->pci_bus = bus;
-	ep->pci_dev_fn = devfn;
-	ep->chip_id = chip_id;
+	ep->pci_bus = pci_bus;
+	ep->pci_dev_fn = pci_devfn;
+#if defined(PCI_SUPPORT_VER2)
+	ep->chip_id = pci_find_slot(pci_bus, pci_devfn)->device;
+#else
+	ep->chip_id = chip_tbl[chip_idx].device_id;
+#endif
 
 	/* Find the connected MII xcvrs.
 	   Doing this in open() would allow detecting external xcvrs later, but
@@ -545,7 +537,6 @@
 	int read_cmd = location |
 		(inl(ee_addr) & 0x40) ? EE_READ64_CMD : EE_READ256_CMD;
 
-	printk("EEctrl is %x.\n", inl(ee_addr));
 	outl(EE_ENB & ~EE_CS, ee_addr);
 	outl(EE_ENB, ee_addr);
 
@@ -930,11 +921,9 @@
 static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 {
 	struct device *dev = (struct device *)dev_instance;
-	struct epic_private *ep;
-	int status, ioaddr, boguscnt = max_interrupt_work;
-
-	ioaddr = dev->base_addr;
-	ep = (struct epic_private *)dev->priv;
+	struct epic_private *ep = (struct epic_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int status, boguscnt = max_interrupt_work;
 
 #if defined(__i386__)
 	/* A lock to prevent simultaneous entry bug on Intel SMP machines. */
@@ -1340,12 +1329,18 @@
 
 	if (loc->bus != LOC_PCI) return NULL;
 	bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
-	printk(KERN_INFO "epic_attach(bus %d, function %d)\n", bus, devfn);
+	printk(KERN_DEBUG "epic_attach(bus %d, function %d)\n", bus, devfn);
 	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
 	pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
 	pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
 	io &= ~3;
-	dev = epic_probe1(bus, devfn, NULL, -1);
+	if (io == 0 || irq == 0) {
+		printk(KERN_ERR "The EPIC/C CardBus Ethernet interface was not "
+			   "assigned an %s.\n" KERN_ERR "  It will not be activated.\n",
+			   io == 0 ? "I/O address" : "IRQ");
+		return NULL;
+	}
+	dev = epic_probe1(bus, devfn, NULL, io, irq, 2, -1);
 	if (dev) {
 		dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
 		strcpy(node->dev_name, dev->name);
@@ -1410,14 +1405,10 @@
 
 #ifdef MODULE
 
-/* An additional parameter that may be passed in... */
-static int debug = -1;
-
-int
-init_module(void)
+int init_module(void)
 {
-	if (debug >= 0)
-		epic_debug = debug;
+	if (epic_debug)
+		printk(KERN_INFO "%s", version);
 
 #ifdef CARDBUS
 	register_driver(&epic_ops);
@@ -1427,8 +1418,7 @@
 #endif
 }
 
-void
-cleanup_module(void)
+void cleanup_module(void)
 {
 	struct device *next_dev;
 
@@ -1438,11 +1428,13 @@
 
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 	while (root_epic_dev) {
-		next_dev = ((struct epic_private *)root_epic_dev->priv)->next_module;
+		struct epic_private *ep = (struct epic_private *)root_epic_dev->priv;
+		next_dev = ep->next_module;
 		unregister_netdev(root_epic_dev);
 		release_region(root_epic_dev->base_addr, EPIC_TOTAL_SIZE);
 		kfree(root_epic_dev);
 		root_epic_dev = next_dev;
+		kfree(ep);
 	}
 }
 
diff -urN linux-2.0.37-pre3/drivers/pci/pci.c linux-2.0.37-pre4/drivers/pci/pci.c
--- linux-2.0.37-pre3/drivers/pci/pci.c	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/pci/pci.c	2003-08-15 15:04:28.000000000 -0700
@@ -328,6 +328,7 @@
 	DEVICE( TRUEVISION,	TRUEVISION_T1000,"TARGA 1000"),
 	DEVICE( INIT,		INIT_320P,	"320 P"),
 	DEVICE( INIT,		INIT_360P,	"360 P"),
+	DEVICE(	TTI,		TTI_HPT343,	"HPT343"),
 	DEVICE( VIA,		VIA_82C505,	"VT 82C505"),
 	DEVICE( VIA,		VIA_82C561,	"VT 82C561"),
 	DEVICE( VIA,		VIA_82C586_1,	"VT 82C586 Apollo IDE"),
@@ -527,6 +528,7 @@
 	DEVICE( ADAPTEC,	ADAPTEC_7850,	"AIC-7850"),
 	DEVICE( ADAPTEC,	ADAPTEC_7855,	"AIC-7855"),
 	DEVICE( ADAPTEC,	ADAPTEC_5800,	"AIC-5800"),
+	DEVICE( ADAPTEC,	ADAPTEC_1480A,	"AIC-1480A"),
 	DEVICE( ADAPTEC,	ADAPTEC_7860,	"AIC-7860"),
 	DEVICE( ADAPTEC,	ADAPTEC_7861,	"AIC-7861"),
 	DEVICE( ADAPTEC,	ADAPTEC_7870,	"AIC-7870"),
@@ -544,6 +546,7 @@
   DEVICE( ADAPTEC2, ADAPTEC2_2940U2, "AHA-2940U2"),
   DEVICE( ADAPTEC2, ADAPTEC2_7890, "AIC-7890/1"),
   DEVICE( ADAPTEC2, ADAPTEC2_3940U2, "AHA-3940U2"),
+  DEVICE( ADAPTEC2, ADAPTEC2_3950U2D, "AHA-3950U2D"),
   DEVICE( ADAPTEC2, ADAPTEC2_7896, "AIC-7896/7"),
   	DEVICE( ATRONICS,	ATRONICS_2015,	"IDE-2015PL"),
 	DEVICE( TIGERJET,	TIGERJET_300,	"Tiger300 ISDN"),
@@ -810,6 +813,7 @@
 	      case PCI_VENDOR_ID_REALTEK:	return "Realtek";
 	      case PCI_VENDOR_ID_TRUEVISION:	return "Truevision";
 	      case PCI_VENDOR_ID_INIT:		return "Initio Corp";
+	      case PCI_VENDOR_ID_TTI:		return "Triones Technologies, Inc.";
 	      case PCI_VENDOR_ID_VIA:		return "VIA Technologies";
 	      case PCI_VENDOR_ID_SMC2:          return "SMC";
 	      case PCI_VENDOR_ID_VORTEX:	return "VORTEX";
@@ -825,6 +829,7 @@
 	      case PCI_VENDOR_ID_RENDITION:	return "Rendition";
 	      case PCI_VENDOR_ID_TOSHIBA:	return "Toshiba";
 	      case PCI_VENDOR_ID_RICOH:		return "Ricoh";
+	      case PCI_VENDOR_ID_ARTOP:	return "Artop Electronics";
 	      case PCI_VENDOR_ID_ZEITNET:	return "ZeitNet";
 	      case PCI_VENDOR_ID_OMEGA:		return "Omega Micro";
 	      case PCI_VENDOR_ID_NP:		return "Network Peripherals";
diff -urN linux-2.0.37-pre3/drivers/scsi/aic7xxx.c linux-2.0.37-pre4/drivers/scsi/aic7xxx.c
--- linux-2.0.37-pre3/drivers/scsi/aic7xxx.c	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/scsi/aic7xxx.c	2003-08-15 15:04:28.000000000 -0700
@@ -354,7 +354,7 @@
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.1.6"
+#define AIC7XXX_C_VERSION  "5.1.7"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -580,6 +580,7 @@
   "Adaptec AHA-294X Ultra2 SCSI host adapter",          /* AIC_7890 */
   "Adaptec AIC-7896/7 Ultra2 SCSI host adapter",        /* AIC_7896 */
   "Adaptec AHA-394X Ultra2 SCSI host adapter",          /* AIC_7897 */
+  "Adaptec AHA-395X Ultra2 SCSI host adapter",          /* AIC_7897 */
   "Adaptec PCMCIA SCSI controller",                     /* card bus stuff */
 };
 
@@ -1509,8 +1510,6 @@
   return( timer->prev != NULL );
 }
 
-#define PCI_DEVICE_ID_ADAPTEC_1480A 0x6075
-
 #endif
 
 static inline unsigned char
@@ -5815,23 +5814,19 @@
        * Put this SCB back on the free list.
        */
       aic7xxx_add_curscb_to_free_list(p);
-      /*
-       * XXX - If we queued an abort tag, go clean up the disconnected list.
-       * We know that this particular SCB had to be the queued abort since
-       * the disconnected SCB would have gotten a reconnect instead.
-       * However, if this is an abort command, then DID_TIMEOUT isn't
-       * appropriate, neither is returning the command for that matter.
-       * What we need to do then is to let the command timeout again so
-       * we get a reset since this abort just failed.
-       */
 #ifdef AIC7XXX_VERBOSE_DEBUGGING
       if (aic7xxx_verbose > 0xffff)
         printk(INFO_LEAD "Selection Timeout.\n", p->host_no, CTL_OF_SCB(scb));
 #endif
-      if (p->flags & SCB_QUEUED_ABORT)
+      if (scb->flags & SCB_QUEUED_ABORT)
       {
+        /*
+         * We know that this particular SCB had to be the queued abort since
+         * the disconnected SCB would have gotten a reconnect instead.
+         * What we need to do then is to let the command timeout again so
+         * we get a reset since this abort just failed.
+         */
         cmd->result = 0;
-        scb->flags &= ~SCB_QUEUED_ABORT;
         scb = NULL;
       }
     }
@@ -7659,7 +7654,7 @@
     aic_outb(p, p->scsi_id_b, SCSIID);
     scsi_conf = aic_inb(p, SCSICONF + 1);
     aic_outb(p, DFON | SPIOEN, SXFRCTL0);
-    aic_outb(p, (scsi_conf & ENSPCHK) | term | 
+    aic_outb(p, (scsi_conf & ENSPCHK) | STIMESEL | term | 
          ENSTIMER | ACTNEGEN, SXFRCTL1);
     aic_outb(p, 0, SIMODE0);
     aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
@@ -7676,7 +7671,7 @@
     aic_outb(p, p->scsi_id, SCSIID);
   scsi_conf = aic_inb(p, SCSICONF);
   aic_outb(p, DFON | SPIOEN, SXFRCTL0);
-  aic_outb(p, (scsi_conf & ENSPCHK) | term | 
+  aic_outb(p, (scsi_conf & ENSPCHK) | STIMESEL | term | 
        ENSTIMER | ACTNEGEN, SXFRCTL1);
   aic_outb(p, 0, SIMODE0);
   aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
@@ -8856,9 +8851,13 @@
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
        AHC_AIC7896_FE,                                      23,
        32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7896_FE,                                      24,
+       32, C56_66 },
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860,
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
-       AHC_AIC7860_FE,                                      24,
+       AHC_AIC7860_FE,                                      25,
        32, C46 },
     };
 
@@ -9104,6 +9103,7 @@
             case 15:
             case 18:
             case 19:
+            case 20:
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
               if (PCI_FUNC(temp_p->pdev->devfn) != 0)
               {
@@ -9271,13 +9271,10 @@
           }
 
           /*
-           * We do another switch based on i so that we can exclude all
-           * 3895 devices from the next option since the 3895 cards use
-           * shared external SCB RAM while all other cards have dedicated
-           * external SCB RAM per channel.  Also exclude the 7850 and
-           * 7860 based stuff since they can have garbage in the bit
-           * that indicates external RAM and get some of this stuff
-           * wrong as a result.
+           * We only support external SCB RAM on the 7895/6/7 chipsets.
+           * We could support it on the 7890/1 easy enough, but I don't
+           * know of any 7890/1 based cards that have it.  I do know
+           * of 7895/6/7 cards that have it and they work properly.
            */
           switch(temp_p->chip & AHC_CHIPID_MASK)
           {
diff -urN linux-2.0.37-pre3/drivers/scsi/aic7xxx_proc.c linux-2.0.37-pre4/drivers/scsi/aic7xxx_proc.c
--- linux-2.0.37-pre3/drivers/scsi/aic7xxx_proc.c	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/scsi/aic7xxx_proc.c	2003-08-15 15:04:28.000000000 -0700
@@ -132,7 +132,8 @@
   {
     for (lun = 0; lun < MAX_LUNS; lun++)
     {
-      if (p->stats[target][lun].r_total != 0)
+      if ( ((lun == 0) && (p->dev_flags[target] & DEVICE_PRESENT)) ||
+           (p->stats[target][lun].r_total != 0) )
 #ifdef AIC7XXX_PROC_STATS
         size += 512;
 #else
@@ -278,7 +279,8 @@
     for (lun = 0; lun < MAX_LUNS; lun++)
     {
       sp = &p->stats[target][lun];
-      if (sp->r_total == 0)
+      if ( (!(p->dev_flags[target] & DEVICE_PRESENT)) ||
+           ((p->stats[target][lun].r_total == 0) && (lun != 0)) )
       {
         continue;
       }
diff -urN linux-2.0.37-pre3/drivers/scsi/DAC960.c linux-2.0.37-pre4/drivers/scsi/DAC960.c
--- linux-2.0.37-pre3/drivers/scsi/DAC960.c	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/scsi/DAC960.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,1979 +0,0 @@
-/*
-
-  Linux Driver for Mylex DAC960 PCI RAID Controllers
-
-  Copyright 1998 by Leonard N. Zubkoff <lnz@dandelion.com>
-
-  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.
-
-  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.
-
-*/
-
-
-#define DAC960_DriverVersion		"2.0.0 Beta3"
-#define DAC960_DriverDate		"29 November 1998"
-
-
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/ioport.h>
-#include <linux/locks.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#include <linux/timer.h>
-#include <linux/pci.h>
-#include <linux/bios32.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include "DAC960.h"
-
-
-/*
-  DAC960_ControllerCount is the number of DAC960 Controllers.
-*/
-
-static int
-  DAC960_ControllerCount =			0;
-
-
-/*
-  DAC960_Controllers is an array of pointers to the DAC960 Controller
-  structures.
-*/
-
-static DAC960_Controller_T
-  *DAC960_Controllers[DAC960_MaxControllers] =	{ NULL };
-
-
-/*
-  DAC960_FileOperations is the File Operations structure for DAC960 Logical
-  Disk Devices.
-*/
-
-static FileOperations_T
-  DAC960_FileOperations =
-    { lseek:		    NULL,
-      read:		    block_read,
-      write:		    block_write,
-      readdir:		    NULL,
-      select:		    NULL,
-      ioctl:		    DAC960_Ioctl,
-      mmap:		    NULL,
-      open:		    DAC960_Open,
-      release:		    DAC960_Release,
-      fsync:		    block_fsync,
-      fasync:		    NULL,
-      check_media_change:   NULL,
-      revalidate:	    NULL };
-
-
-/*
-  DAC960_AnnounceDriver announces the Driver Version and Date, Author's Name,
-  Copyright Notice, and Electronic Mail Address.
-*/
-
-static void DAC960_AnnounceDriver(DAC960_Controller_T *Controller)
-{
-  DAC960_Announce("***** DAC960 RAID Driver Version "
-		  DAC960_DriverVersion " of "
-		  DAC960_DriverDate " *****\n", Controller);
-  DAC960_Announce("Copyright 1998 by Leonard N. Zubkoff "
-		  "<lnz@dandelion.com>\n", Controller);
-}
-
-
-/*
-  DAC960_Failure prints a standardized error message, and then returns false.
-*/
-
-static boolean DAC960_Failure(DAC960_Controller_T *Controller,
-			      char *ErrorMessage)
-{
-  DAC960_Error("While configuring DAC960 PCI RAID Controller at\n",
-	       Controller);
-  if (Controller->IO_Address == 0)
-    DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A "
-		 "PCI Address 0x%X\n", Controller,
-		 Controller->Bus, Controller->Device,
-		 Controller->Function, Controller->PCI_Address);
-  else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address "
-		    "0x%X PCI Address 0x%X\n", Controller,
-		    Controller->Bus, Controller->Device,
-		    Controller->Function, Controller->IO_Address,
-		    Controller->PCI_Address);
-  DAC960_Error("%s FAILED - DETACHING\n", Controller, ErrorMessage);
-  return false;
-}
-
-
-/*
-  DAC960_ClearCommand clears critical fields of Command.
-*/
-
-static inline void DAC960_ClearCommand(DAC960_Command_T *Command)
-{
-  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-  CommandMailbox->Words[0] = 0;
-  CommandMailbox->Words[1] = 0;
-  CommandMailbox->Words[2] = 0;
-  CommandMailbox->Words[3] = 0;
-  Command->CommandStatus = 0;
-}
-
-
-/*
-  DAC960_AllocateCommand allocates a Command structure from Controller's
-  free list.
-*/
-
-static inline DAC960_Command_T *DAC960_AllocateCommand(DAC960_Controller_T
-						       *Controller)
-{
-  DAC960_Command_T *Command = Controller->FreeCommands;
-  if (Command == NULL) return NULL;
-  Controller->FreeCommands = Command->Next;
-  Command->Next = NULL;
-  return Command;
-}
-
-
-/*
-  DAC960_DeallocateCommand deallocates Command, returning it to Controller's
-  free list.
-*/
-
-static inline void DAC960_DeallocateCommand(DAC960_Command_T *Command)
-{
-  DAC960_Controller_T *Controller = Command->Controller;
-  Command->Next = Controller->FreeCommands;
-  Controller->FreeCommands = Command;
-}
-
-
-/*
-  DAC960_QueueCommand queues Command.
-*/
-
-static void DAC960_QueueCommand(DAC960_Command_T *Command)
-{
-  DAC960_Controller_T *Controller = Command->Controller;
-  void *ControllerBaseAddress = Controller->BaseAddress;
-  DAC960_V4_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-  DAC960_V4_CommandMailbox_T *NextCommandMailbox;
-  CommandMailbox->Common.CommandIdentifier = Command - Controller->Commands;
-  switch (Controller->ControllerType)
-    {
-    case DAC960_V4_Controller:
-      NextCommandMailbox = Controller->NextCommandMailbox;
-      DAC960_V4_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
-      if (Controller->PreviousCommandMailbox->Words[0] == 0)
-	DAC960_V4_NewCommand(ControllerBaseAddress);
-      Controller->PreviousCommandMailbox = NextCommandMailbox;
-      if (++NextCommandMailbox > Controller->LastCommandMailbox)
-	NextCommandMailbox = Controller->FirstCommandMailbox;
-      Controller->NextCommandMailbox = NextCommandMailbox;
-      break;
-    case DAC960_V3_Controller:
-      while (DAC960_V3_MailboxFullP(ControllerBaseAddress))
-	udelay(1);
-      DAC960_V3_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox);
-      DAC960_V3_NewCommand(ControllerBaseAddress);
-      break;
-    }
-}
-
-
-/*
-  DAC960_ExecuteCommand executes Command and waits for completion.  It
-  returns true on success and false on failure.
-*/
-
-static boolean DAC960_ExecuteCommand(DAC960_Command_T *Command)
-{
-  Semaphore_T Semaphore = MUTEX_LOCKED;
-  Command->Semaphore = &Semaphore;
-  DAC960_QueueCommand(Command);
-  down(&Semaphore);
-  return Command->CommandStatus == DAC960_NormalCompletion;
-}
-
-
-/*
-  DAC960_ExecuteType3 executes a DAC960 Type 3 Command and waits for
-  completion.  It returns true on success and false on failure.
-*/
-
-static boolean DAC960_ExecuteType3(DAC960_Controller_T *Controller,
-				   DAC960_CommandOpcode_T CommandOpcode,
-				   void *DataPointer)
-{
-  DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
-  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-  boolean Result;
-  DAC960_ClearCommand(Command);
-  Command->CommandType = DAC960_ImmediateCommand;
-  CommandMailbox->Type3.CommandOpcode = CommandOpcode;
-  CommandMailbox->Type3.BusAddress = Virtual_to_Bus(DataPointer);
-  Result = DAC960_ExecuteCommand(Command);
-  DAC960_DeallocateCommand(Command);
-  return Result;
-}
-
-
-/*
-  DAC960_ExecuteType3D executes a DAC960 Type 3D Command and waits for
-  completion.  It returns true on success and false on failure.
-*/
-
-static boolean DAC960_ExecuteType3D(DAC960_Controller_T *Controller,
-				    DAC960_CommandOpcode_T CommandOpcode,
-				    unsigned char Channel,
-				    unsigned char TargetID,
-				    void *DataPointer)
-{
-  DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
-  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-  boolean Result;
-  DAC960_ClearCommand(Command);
-  Command->CommandType = DAC960_ImmediateCommand;
-  CommandMailbox->Type3D.CommandOpcode = CommandOpcode;
-  CommandMailbox->Type3D.Channel = Channel;
-  CommandMailbox->Type3D.TargetID = TargetID;
-  CommandMailbox->Type3D.BusAddress = Virtual_to_Bus(DataPointer);
-  Result = DAC960_ExecuteCommand(Command);
-  DAC960_DeallocateCommand(Command);
-  return Result;
-}
-
-
-/*
-  DAC960_V4_EnableMemoryMailboxInterface enables the V4 Memory Mailbox
-  Interface.
-*/
-
-static boolean DAC960_V4_EnableMemoryMailboxInterface(DAC960_Controller_T
-						      *Controller)
-{
-  void *ControllerBaseAddress = Controller->BaseAddress;
-  DAC960_V4_CommandMailbox_T *CommandMailboxesMemory;
-  DAC960_V4_StatusMailbox_T *StatusMailboxesMemory;
-  DAC960_CommandMailbox_T CommandMailbox;
-  DAC960_CommandStatus_T CommandStatus;
-  CommandMailboxesMemory =
-    (DAC960_V4_CommandMailbox_T *) __get_free_pages(GFP_KERNEL, 1, 0);
-  memset(CommandMailboxesMemory, 0, PAGE_SIZE << 1);
-  Controller->FirstCommandMailbox = CommandMailboxesMemory;
-  CommandMailboxesMemory += DAC960_CommandMailboxCount - 1;
-  Controller->LastCommandMailbox = CommandMailboxesMemory;
-  Controller->NextCommandMailbox = Controller->FirstCommandMailbox;
-  Controller->PreviousCommandMailbox = Controller->LastCommandMailbox;
-  StatusMailboxesMemory =
-    (DAC960_V4_StatusMailbox_T *) (CommandMailboxesMemory + 1);
-  Controller->FirstStatusMailbox = StatusMailboxesMemory;
-  StatusMailboxesMemory += DAC960_StatusMailboxCount - 1;
-  Controller->LastStatusMailbox = StatusMailboxesMemory;
-  Controller->NextStatusMailbox = Controller->FirstStatusMailbox;
-  /* Enable the Memory Mailbox Interface. */
-  CommandMailbox.TypeX.CommandOpcode = 0x2B;
-  CommandMailbox.TypeX.CommandIdentifier = 0;
-  CommandMailbox.TypeX.CommandOpcode2 = 0x10;
-  CommandMailbox.TypeX.CommandMailboxesBusAddress =
-    Virtual_to_Bus(Controller->FirstCommandMailbox);
-  CommandMailbox.TypeX.StatusMailboxesBusAddress =
-    Virtual_to_Bus(Controller->FirstStatusMailbox);
-  while (DAC960_V4_MailboxFullP(ControllerBaseAddress))
-    udelay(1);
-  DAC960_V4_WriteLegacyCommand(ControllerBaseAddress, &CommandMailbox);
-  DAC960_V4_NewCommand(ControllerBaseAddress);
-  while (!DAC960_V4_StatusAvailableP(ControllerBaseAddress))
-    udelay(1);
-  CommandStatus = DAC960_V4_ReadStatusRegister(ControllerBaseAddress);
-  DAC960_V4_AcknowledgeInterrupt(ControllerBaseAddress);
-  DAC960_V4_AcknowledgeStatus(ControllerBaseAddress);
-  return CommandStatus == DAC960_NormalCompletion;
-}
-
-
-/*
-  DAC960_DetectControllers detects DAC960 PCI RAID Controllers by interrogating
-  the PCI Configuration Space for DeviceID.
-*/
-
-static void DAC960_DetectControllers(unsigned short DeviceID)
-{
-  unsigned char Bus, DeviceFunction, IRQ_Channel;
-  unsigned int BaseAddress0, BaseAddress1;
-  unsigned int MemoryWindowSize = 0;
-  unsigned short Index = 0;
-  while (pcibios_find_device(PCI_VENDOR_ID_MYLEX, DeviceID,
-			     Index++, &Bus, &DeviceFunction) == 0)
-    {
-      DAC960_Controller_T *Controller = (DAC960_Controller_T *)
-	kmalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC);
-      DAC960_ControllerType_T ControllerType = 0;
-      DAC960_IO_Address_T IO_Address = 0;
-      DAC960_PCI_Address_T PCI_Address = 0;
-      unsigned char Device = DeviceFunction >> 3;
-      unsigned char Function = DeviceFunction & 0x7;
-      pcibios_read_config_dword(Bus, DeviceFunction,
-				PCI_BASE_ADDRESS_0, &BaseAddress0);
-      pcibios_read_config_dword(Bus, DeviceFunction,
-				PCI_BASE_ADDRESS_1, &BaseAddress1);
-      pcibios_read_config_byte(Bus, DeviceFunction,
-			       PCI_INTERRUPT_LINE, &IRQ_Channel);
-      switch (DeviceID)
-	{
-	case PCI_DEVICE_ID_MYLEX_DAC960P_V4:
-	  ControllerType = DAC960_V4_Controller;
-	  PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
-	  MemoryWindowSize = DAC960_V4_RegisterWindowSize;
-	  break;
-	case PCI_DEVICE_ID_MYLEX_DAC960P_V3:
-	  ControllerType = DAC960_V3_Controller;
-	  IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
-	  PCI_Address = BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
-	  MemoryWindowSize = DAC960_V3_RegisterWindowSize;
-	  break;
-	}
-      if (DAC960_ControllerCount == DAC960_MaxControllers)
-	{
-	  DAC960_Error("More than %d DAC960 Controllers detected - "
-		       "ignoring from Controller at\n",
-		       NULL, DAC960_MaxControllers);
-	  goto Failure;
-	}
-      if (Controller == NULL)
-	{
-	  DAC960_Error("Unable to allocate Controller structure for "
-		       "Controller at\n", NULL);
-	  goto Failure;
-	}
-      memset(Controller, 0, sizeof(DAC960_Controller_T));
-      Controller->ControllerNumber = DAC960_ControllerCount;
-      DAC960_Controllers[DAC960_ControllerCount++] = Controller;
-      if (IRQ_Channel == 0 || IRQ_Channel >= NR_IRQS)
-	{
-	  DAC960_Error("IRQ Channel %d illegal for Controller at\n",
-		       NULL, IRQ_Channel);
-	  goto Failure;
-	}
-      Controller->ControllerType = ControllerType;
-      Controller->IO_Address = IO_Address;
-      Controller->PCI_Address = PCI_Address;
-      Controller->Bus = Bus;
-      Controller->Device = Device;
-      Controller->Function = Function;
-      /*
-	Acquire shared access to the IRQ Channel.
-      */
-      strcpy(Controller->FullModelName, "DAC960");
-      if (request_irq(IRQ_Channel, DAC960_InterruptHandler,
-		      SA_INTERRUPT | SA_SHIRQ, Controller->FullModelName,
-		      Controller) < 0)
-	{
-	  DAC960_Error("Unable to acquire IRQ Channel %d for Controller at\n",
-		       NULL, IRQ_Channel);
-	  goto Failure;
-	}
-      Controller->IRQ_Channel = IRQ_Channel;
-      /*
-	Map the Controller Register Window.
-      */
-      if (MemoryWindowSize < PAGE_SIZE)
-	MemoryWindowSize = PAGE_SIZE;
-      Controller->MemoryMappedAddress =
-	ioremap_nocache(PCI_Address & PAGE_MASK, MemoryWindowSize);
-      Controller->BaseAddress =
-	Controller->MemoryMappedAddress + (PCI_Address & ~PAGE_MASK);
-      if (Controller->MemoryMappedAddress == NULL)
-	{
-	  DAC960_Error("Unable to map Controller Register Window for "
-		       "Controller at\n", NULL);
-	  goto Failure;
-	}
-      switch (DeviceID)
-	{
-	case PCI_DEVICE_ID_MYLEX_DAC960P_V4:
-	  DAC960_V4_DisableInterrupts(Controller->BaseAddress);
-	  if (!DAC960_V4_EnableMemoryMailboxInterface(Controller))
-	    {
-	      DAC960_Error("Unable to Enable V4 Memory Mailbox Interface "
-			   "for Controller at\n", NULL);
-	      goto Failure;
-	    }
-	  DAC960_V4_EnableInterrupts(Controller->BaseAddress);
-	  break;
-	case PCI_DEVICE_ID_MYLEX_DAC960P_V3:
-	  request_region(Controller->IO_Address, 0x80,
-			 Controller->FullModelName);
-	  DAC960_V3_EnableInterrupts(Controller->BaseAddress);
-	  break;
-	}
-      Controller->Commands[0].Controller = Controller;
-      Controller->Commands[0].Next = NULL;
-      Controller->FreeCommands = &Controller->Commands[0];
-      continue;
-    Failure:
-      if (IO_Address == 0)
-	DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A "
-		     "PCI Address 0x%X\n", NULL,
-		     Bus, Device, Function, PCI_Address);
-      else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address "
-			"0x%X PCI Address 0x%X\n", NULL,
-			Bus, Device, Function, IO_Address, PCI_Address);
-      if (Controller == NULL) break;
-      if (Controller->IRQ_Channel > 0)
-	free_irq(IRQ_Channel, Controller);
-      if (Controller->MemoryMappedAddress != NULL)
-	iounmap(Controller->MemoryMappedAddress);
-      kfree(Controller);
-      break;
-    }
-}
-
-
-/*
-  DAC960_ReadControllerConfiguration reads the Configuration Information
-  from Controller and initializes the Controller structure.
-*/
-
-static boolean DAC960_ReadControllerConfiguration(DAC960_Controller_T
-						  *Controller)
-{
-  DAC960_Enquiry2_T Enquiry2;
-  DAC960_Config2_T Config2;
-  int Channel, TargetID;
-  if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry,
-			   &Controller->Enquiry[0]))
-    return DAC960_Failure(Controller, "ENQUIRY");
-  if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry2, &Enquiry2))
-    return DAC960_Failure(Controller, "ENQUIRY2");
-  if (!DAC960_ExecuteType3(Controller, DAC960_ReadConfig2, &Config2))
-    return DAC960_Failure(Controller, "READ CONFIG2");
-  if (!DAC960_ExecuteType3(Controller, DAC960_GetLogicalDriveInformation,
-			   &Controller->LogicalDriveInformation[0]))
-    return DAC960_Failure(Controller, "GET LOGICAL DRIVE INFORMATION");
-  for (Channel = 0; Channel < Enquiry2.ActualChannels; Channel++)
-    for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++)
-      if (!DAC960_ExecuteType3D(Controller, DAC960_GetDeviceState,
-				Channel, TargetID,
-				&Controller->DeviceState[0][Channel][TargetID]))
-	  return DAC960_Failure(Controller, "GET DEVICE STATE");
-  /*
-    Initialize the Controller Model Name and Full Model Name fields.
-  */
-  switch (Enquiry2.HardwareID.SubModel)
-    {
-    case DAC960_P_PD_PU:
-      if (Enquiry2.SCSICapability.BusSpeed == DAC960_Ultra)
-	strcpy(Controller->ModelName, "DAC960PU");
-      else strcpy(Controller->ModelName, "DAC960PD");
-      break;
-    case DAC960_PL:
-      strcpy(Controller->ModelName, "DAC960PL");
-      break;
-    case DAC960_PG:
-      strcpy(Controller->ModelName, "DAC960PG");
-      break;
-    case DAC960_PJ:
-      strcpy(Controller->ModelName, "DAC960PJ");
-      break;
-    case DAC960_PTL_0:
-      strcpy(Controller->ModelName, "DAC960PTL-0");
-      break;
-    case DAC960_PTL_1:
-      strcpy(Controller->ModelName, "DAC960PTL-1");
-      break;
-    default:
-      return DAC960_Failure(Controller, "MODEL VERIFICATION");
-    }
-  strcpy(Controller->FullModelName, "Mylex ");
-  strcat(Controller->FullModelName, Controller->ModelName);
-  /*
-    Initialize the Controller Firmware Version field and verify that it
-    is a supported firmware version.  The supported firmware versions are:
-
-    DAC960PTL/PJ/PG	4.06 and above
-    DAC960PU/PD/PL	3.51 and above
-  */
-  sprintf(Controller->FirmwareVersion, "%d.%02d-%c-%02d",
-	  Enquiry2.FirmwareID.MajorVersion, Enquiry2.FirmwareID.MinorVersion,
-	  Enquiry2.FirmwareID.FirmwareType, Enquiry2.FirmwareID.TurnID);
-  if (!((Controller->FirmwareVersion[0] == '4' &&
-	 strcmp(Controller->FirmwareVersion, "4.06") >= 0) ||
-	(Controller->FirmwareVersion[0] == '3' &&
-	 strcmp(Controller->FirmwareVersion, "3.51") >= 0)))
-    {
-      DAC960_Failure(Controller, "FIRMWARE VERSION VERIFICATION");
-      DAC960_Error("Firmware Version = '%s'\n", Controller,
-		   Controller->FirmwareVersion);
-      return false;
-    }
-  /*
-    Initialize the Controller Channels, Memory Size, and SAF-TE Fault
-    Management Enabled fields.
-  */
-  Controller->Channels = Enquiry2.ActualChannels;
-  Controller->MemorySize = Enquiry2.MemorySize >> 20;
-  Controller->SAFTE_FaultManagementEnabled =
-    Enquiry2.FaultManagementType == DAC960_SAFTE;
-  /*
-    Initialize the Controller Queue Depth, Driver Queue Depth, Logical Drive
-    Count, Maximum Blocks per Command, and Maximum Scatter/Gather Segments.
-    The Driver Queue Depth must be at most one less than the Controller Queue
-    Depth to allow for an automatic drive rebuild operation.
-  */
-  Controller->ControllerQueueDepth = Controller->Enquiry[0].MaxCommands;
-  Controller->DriverQueueDepth = Controller->ControllerQueueDepth - 1;
-  Controller->LogicalDriveCount = Controller->Enquiry[0].NumberOfLogicalDrives;
-  Controller->MaxBlocksPerCommand = Enquiry2.MaxBlocksPerCommand;
-  Controller->MaxScatterGatherSegments = Enquiry2.MaxScatterGatherEntries;
-  /*
-    Initialize the Stripe Size, Segment Size, and Geometry Translation.
-  */
-  Controller->StripeSize = Config2.BlocksPerStripe * Config2.BlockFactor
-			   >> (10 - DAC960_BlockSizeBits);
-  Controller->SegmentSize = Config2.BlocksPerCacheLine * Config2.BlockFactor
-			    >> (10 - DAC960_BlockSizeBits);
-  switch (Config2.DriveGeometry)
-    {
-    case DAC960_Geometry_128_32:
-      Controller->GeometryTranslationHeads = 128;
-      Controller->GeometryTranslationSectors = 32;
-      break;
-    case DAC960_Geometry_255_63:
-      Controller->GeometryTranslationHeads = 255;
-      Controller->GeometryTranslationSectors = 63;
-      break;
-    default:
-      return DAC960_Failure(Controller, "CONFIG2 DRIVE GEOMETRY");
-    }
-  return true;
-}
-
-
-/*
-  DAC960_ReportControllerConfiguration reports the configuration of
-  Controller.
-*/
-
-static boolean DAC960_ReportControllerConfiguration(DAC960_Controller_T
-						    *Controller)
-{
-  int LogicalDriveNumber, Channel, TargetID;
-  DAC960_Info("Configuring Mylex %s PCI RAID Controller\n",
-	      Controller, Controller->ModelName);
-  DAC960_Info("  Firmware Version: %s, Channels: %d, Memory Size: %dMB\n",
-	      Controller, Controller->FirmwareVersion,
-	      Controller->Channels, Controller->MemorySize);
-  DAC960_Info("  PCI Bus: %d, Device: %d, Function: %d, I/O Address: ",
-	      Controller, Controller->Bus,
-	      Controller->Device, Controller->Function);
-  if (Controller->IO_Address == 0)
-    DAC960_Info("Unassigned\n", Controller);
-  else DAC960_Info("0x%X\n", Controller, Controller->IO_Address);
-  DAC960_Info("  PCI Address: 0x%X mapped at 0x%lX, IRQ Channel: %d\n",
-	      Controller, Controller->PCI_Address,
-	      (unsigned long) Controller->BaseAddress,
-	      Controller->IRQ_Channel);
-  DAC960_Info("  Controller Queue Depth: %d, "
-	      "Maximum Blocks per Command: %d\n",
-	      Controller, Controller->ControllerQueueDepth,
-	      Controller->MaxBlocksPerCommand);
-  DAC960_Info("  Driver Queue Depth: %d, "
-	      "Maximum Scatter/Gather Segments: %d\n",
-	      Controller, Controller->DriverQueueDepth,
-	      Controller->MaxScatterGatherSegments);
-  DAC960_Info("  Stripe Size: %dKB, Segment Size: %dKB, "
-	      "BIOS Geometry: %d/%d\n", Controller,
-	      Controller->StripeSize,
-	      Controller->SegmentSize,
-	      Controller->GeometryTranslationHeads,
-	      Controller->GeometryTranslationSectors);
-  if (Controller->SAFTE_FaultManagementEnabled)
-    DAC960_Info("  SAF-TE Fault Management Enabled\n", Controller);
-  DAC960_Info("  Physical Devices:\n", Controller);
-  for (Channel = 0; Channel < Controller->Channels; Channel++)
-    for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++)
-      {
-	DAC960_DeviceState_T *DeviceState =
-	  &Controller->DeviceState[0][Channel][TargetID];
-	if (!DeviceState->Present) continue;
-	switch (DeviceState->DeviceType)
-	  {
-	  case DAC960_OtherType:
-	    DAC960_Info("    %d:%d - Other\n", Controller, Channel, TargetID);
-	    break;
-	  case DAC960_DiskType:
-	    DAC960_Info("    %d:%d - Disk: %s, %d blocks\n", Controller,
-			Channel, TargetID,
-			(DeviceState->DeviceState == DAC960_Device_Dead
-			 ? "Dead"
-			 : DeviceState->DeviceState == DAC960_Device_WriteOnly
-			   ? "Write-Only"
-			   : DeviceState->DeviceState == DAC960_Device_Online
-			     ? "Online" : "Standby"),
-			DeviceState->DiskSize);
-	    break;
-	  case DAC960_SequentialType:
-	    DAC960_Info("    %d:%d - Sequential\n", Controller,
-			Channel, TargetID);
-	    break;
-	  case DAC960_CDROM_or_WORM_Type:
-	    DAC960_Info("    %d:%d - CD-ROM or WORM\n", Controller,
-			Channel, TargetID);
-	    break;
-	  }
-
-      }
-  DAC960_Info("  Logical Drives:\n", Controller);
-  for (LogicalDriveNumber = 0;
-       LogicalDriveNumber < Controller->LogicalDriveCount;
-       LogicalDriveNumber++)
-    {
-      DAC960_LogicalDriveInformation_T *LogicalDriveInformation =
-	&Controller->LogicalDriveInformation[0][LogicalDriveNumber];
-      DAC960_Info("    /dev/rd/c%dd%d: RAID-%d, %s, %d blocks, %s\n",
-		  Controller, Controller->ControllerNumber, LogicalDriveNumber,
-		  LogicalDriveInformation->RAIDLevel,
-		  (LogicalDriveInformation->LogicalDriveState ==
-		     DAC960_LogicalDrive_Online
-		   ? "Online"
-		   : LogicalDriveInformation->LogicalDriveState ==
-		     DAC960_LogicalDrive_Critical
-		     ? "Critical" : "Offline"),
-		  LogicalDriveInformation->LogicalDriveSize,
-		  (LogicalDriveInformation->WriteBack
-		   ? "Write Back" : "Write Thru"));
-    }
-  DAC960_Info("\n", Controller);
-  return true;
-}
-
-
-/*
-  DAC960_RegisterBlockDevice registers the Block Device structures
-  associated with Controller.
-*/
-
-static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
-{
-  static void (*RequestFunctions[DAC960_MaxControllers])(void) =
-    { DAC960_RequestFunction0, DAC960_RequestFunction1,
-      DAC960_RequestFunction2, DAC960_RequestFunction3,
-      DAC960_RequestFunction4, DAC960_RequestFunction5,
-      DAC960_RequestFunction6, DAC960_RequestFunction7 };
-  int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
-  GenericDiskInfo_T *GenericDiskInfo;
-  int MinorNumber;
-  /*
-    Register the Block Device Major Number for this DAC960 Controller.
-  */
-  if (register_blkdev(MajorNumber, "rd", &DAC960_FileOperations) < 0)
-    {
-      DAC960_Error("UNABLE TO ACQUIRE MAJOR NUMBER %d - DETACHING\n",
-		   Controller, MajorNumber);
-      return false;
-    }
-  /*
-    Initialize the I/O Request Function.
-  */
-  blk_dev[MajorNumber].request_fn =
-    RequestFunctions[Controller->ControllerNumber];
-  /*
-    Initialize the Disk Partitions array, Partition Sizes array, Block Sizes
-    array, Max Sectors per Request array, and Max Segments per Request array.
-  */
-  for (MinorNumber = 0; MinorNumber < DAC960_MinorCount; MinorNumber++)
-    {
-      Controller->BlockSizes[MinorNumber] = BLOCK_SIZE;
-      Controller->MaxSectorsPerRequest[MinorNumber] =
-	Controller->MaxBlocksPerCommand;
-      Controller->MaxSegmentsPerRequest[MinorNumber] =
-	Controller->MaxScatterGatherSegments;
-    }
-  Controller->GenericDiskInfo.part = Controller->DiskPartitions;
-  Controller->GenericDiskInfo.sizes = Controller->PartitionSizes;
-  blksize_size[MajorNumber] = Controller->BlockSizes;
-  max_sectors[MajorNumber] = Controller->MaxSectorsPerRequest;
-  max_segments[MajorNumber] = Controller->MaxSegmentsPerRequest;
-  /*
-    Initialize Read Ahead to 128 sectors.
-  */
-  read_ahead[MajorNumber] = 128;
-  /*
-    Complete initialization of the Generic Disk Information structure.
-  */
-  Controller->GenericDiskInfo.major = MajorNumber;
-  Controller->GenericDiskInfo.major_name = "rd";
-  Controller->GenericDiskInfo.minor_shift = DAC960_MaxPartitionsBits;
-  Controller->GenericDiskInfo.max_p = DAC960_MaxPartitions;
-  Controller->GenericDiskInfo.max_nr = DAC960_MaxLogicalDrives;
-  Controller->GenericDiskInfo.init = DAC960_InitializeGenericDiskInfo;
-  Controller->GenericDiskInfo.nr_real = Controller->LogicalDriveCount;
-  Controller->GenericDiskInfo.real_devices = Controller;
-  Controller->GenericDiskInfo.next = NULL;
-  /*
-    Install the Generic Disk Information structure at the end of the list.
-  */
-  if ((GenericDiskInfo = gendisk_head) != NULL)
-    {
-      while (GenericDiskInfo->next != NULL)
-	GenericDiskInfo = GenericDiskInfo->next;
-      GenericDiskInfo->next = &Controller->GenericDiskInfo;
-    }
-  else gendisk_head = &Controller->GenericDiskInfo;
-  /*
-    Indicate the Block Device Registration completed successfully,
-  */
-  return true;
-}
-
-
-/*
-  DAC960_UnregisterBlockDevice unregisters the Block Device structures
-  associated with Controller.
-*/
-
-static void DAC960_UnregisterBlockDevice(DAC960_Controller_T *Controller)
-{
-  int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
-  /*
-    Unregister the Block Device Major Number for this DAC960 Controller.
-  */
-  unregister_blkdev(MajorNumber, "rd");
-  /*
-    Remove the I/O Request Function.
-  */
-  blk_dev[MajorNumber].request_fn = NULL;
-  /*
-    Remove the Disk Partitions array, Partition Sizes array, Block Sizes
-    array, Max Sectors per Request array, and Max Segments per Request array.
-  */
-  Controller->GenericDiskInfo.part = NULL;
-  Controller->GenericDiskInfo.sizes = NULL;
-  blk_size[MajorNumber] = NULL;
-  blksize_size[MajorNumber] = NULL;
-  max_sectors[MajorNumber] = NULL;
-  max_segments[MajorNumber] = NULL;
-  /*
-    Remove the Generic Disk Information structure from the list.
-  */
-  if (gendisk_head != &Controller->GenericDiskInfo)
-    {
-      GenericDiskInfo_T *GenericDiskInfo = gendisk_head;
-      while (GenericDiskInfo != NULL &&
-	     GenericDiskInfo->next != &Controller->GenericDiskInfo)
-	GenericDiskInfo = GenericDiskInfo->next;
-      if (GenericDiskInfo != NULL)
-	GenericDiskInfo->next = GenericDiskInfo->next->next;
-    }
-  else gendisk_head = Controller->GenericDiskInfo.next;
-}
-
-
-/*
-  DAC960_InitializeController initializes Controller.
-*/
-
-static void DAC960_InitializeController(DAC960_Controller_T *Controller)
-{
-  DAC960_AnnounceDriver(Controller);
-  if (DAC960_ReadControllerConfiguration(Controller) &&
-      DAC960_ReportControllerConfiguration(Controller) &&
-      DAC960_RegisterBlockDevice(Controller))
-    {
-      /*
-	Initialize the Command structures.
-      */
-      DAC960_Command_T *Commands = Controller->Commands;
-      int CommandIdentifier;
-      Controller->FreeCommands = NULL;
-      for (CommandIdentifier = 0;
-	   CommandIdentifier < Controller->DriverQueueDepth;
-	   CommandIdentifier++)
-	{
-	  Commands[CommandIdentifier].Controller = Controller;
-	  Commands[CommandIdentifier].Next = Controller->FreeCommands;
-	  Controller->FreeCommands = &Commands[CommandIdentifier];
-	}
-      /*
-	Initialize the Monitoring Timer.
-      */
-      init_timer(&Controller->MonitoringTimer);
-      Controller->MonitoringTimer.expires =
-	jiffies + DAC960_MonitoringTimerInterval;
-      Controller->MonitoringTimer.data = (unsigned long) Controller;
-      Controller->MonitoringTimer.function = DAC960_MonitoringTimerFunction;
-      add_timer(&Controller->MonitoringTimer);
-    }
-  else
-    {
-      free_irq(Controller->IRQ_Channel, Controller);
-      iounmap(Controller->MemoryMappedAddress);
-      DAC960_UnregisterBlockDevice(Controller);
-      DAC960_Controllers[Controller->ControllerNumber] = NULL;
-      kfree(Controller);
-    }
-}
-
-
-/*
-  DAC960_Initialize initializes the DAC960 Driver.
-*/
-
-void DAC960_Initialize(void)
-{
-  int ControllerNumber;
-  DAC960_DetectControllers(PCI_DEVICE_ID_MYLEX_DAC960P_V4);
-  DAC960_DetectControllers(PCI_DEVICE_ID_MYLEX_DAC960P_V3);
-  for (ControllerNumber = 0;
-       ControllerNumber < DAC960_ControllerCount;
-       ControllerNumber++)
-    if (DAC960_Controllers[ControllerNumber] != NULL)
-      DAC960_InitializeController(DAC960_Controllers[ControllerNumber]);
-}
-
-
-/*
-  DAC960_Finalize flushes all DAC960 caches before the system halts.
-*/
-
-void DAC960_Finalize(void)
-{
-  int ControllerNumber;
-  for (ControllerNumber = 0;
-       ControllerNumber < DAC960_ControllerCount;
-       ControllerNumber++)
-    {
-      DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
-      if (Controller == NULL) continue;
-      DAC960_Notice("Flushing Cache...", Controller);
-      DAC960_ExecuteType3(Controller, DAC960_Flush, NULL);
-      DAC960_Notice("done\n", Controller);
-    }
-}
-
-
-/*
-  DAC960_ProcessRequest attempts to remove one I/O Request from Controller's
-  I/O Request Queue and queues it to the Controller.  Command is either a
-  previously allocated Command to be reused, or NULL if a new Command is to
-  be allocated for this I/O Request.  It returns true if an I/O Request was
-  queued and false otherwise.
-*/
-
-static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller,
-				     DAC960_Command_T *Command)
-{
-  int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
-  IO_Request_T *Request = blk_dev[MajorNumber].current_request;
-  DAC960_CommandMailbox_T *CommandMailbox;
-  char *RequestBuffer;
-  if (Request == NULL || Request->rq_status == RQ_INACTIVE) return false;
-  if (Command == NULL)
-    Command = DAC960_AllocateCommand(Controller);
-  if (Command == NULL) return false;
-  DAC960_ClearCommand(Command);
-  if (Request->cmd == READ)
-    Command->CommandType = DAC960_ReadCommand;
-  else Command->CommandType = DAC960_WriteCommand;
-  Command->Semaphore = Request->sem;
-  Command->LogicalDriveNumber = DAC960_LogicalDriveNumber(Request->rq_dev);
-  Command->BlockNumber =
-    Request->sector
-    + Controller->GenericDiskInfo.part[MINOR(Request->rq_dev)].start_sect;
-  Command->BlockCount = Request->nr_sectors;
-  Command->SegmentCount = Request->nr_segments;
-  Command->BufferHeader = Request->bh;
-  RequestBuffer = Request->buffer;
-  Request->rq_status = RQ_INACTIVE;
-  blk_dev[MajorNumber].current_request = Request->next;
-  wake_up(&wait_for_request);
-  CommandMailbox = &Command->CommandMailbox;
-  if (Command->SegmentCount == 1)
-    {
-      if (Command->CommandType == DAC960_ReadCommand)
-	CommandMailbox->Type5.CommandOpcode = DAC960_Read;
-      else CommandMailbox->Type5.CommandOpcode = DAC960_Write;
-      CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
-      CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
-      CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
-      CommandMailbox->Type5.BusAddress = Virtual_to_Bus(RequestBuffer);
-    }
-  else
-    {
-      DAC960_ScatterGatherSegment_T
-	*ScatterGatherList = Command->ScatterGatherList;
-      BufferHeader_T *BufferHeader = Command->BufferHeader;
-      char *LastDataEndPointer = NULL;
-      int SegmentNumber = 0;
-      if (Command->CommandType == DAC960_ReadCommand)
-	CommandMailbox->Type5.CommandOpcode = DAC960_ReadWithOldScatterGather;
-      else
-	CommandMailbox->Type5.CommandOpcode = DAC960_WriteWithOldScatterGather;
-      CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
-      CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
-      CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
-      CommandMailbox->Type5.BusAddress = Virtual_to_Bus(ScatterGatherList);
-      CommandMailbox->Type5.ScatterGatherCount = Command->SegmentCount;
-      while (BufferHeader != NULL)
-	{
-	  if (BufferHeader->b_data == LastDataEndPointer)
-	    {
-	      ScatterGatherList[SegmentNumber-1].SegmentByteCount +=
-		BufferHeader->b_size;
-	      LastDataEndPointer += BufferHeader->b_size;
-	    }
-	  else
-	    {
-	      ScatterGatherList[SegmentNumber].SegmentDataPointer =
-		Virtual_to_Bus(BufferHeader->b_data);
-	      ScatterGatherList[SegmentNumber].SegmentByteCount =
-		BufferHeader->b_size;
-	      LastDataEndPointer = BufferHeader->b_data + BufferHeader->b_size;
-	      if (SegmentNumber++ > Controller->MaxScatterGatherSegments)
-		panic("DAC960: Scatter/Gather Segment Overflow\n");
-	    }
-	  BufferHeader = BufferHeader->b_reqnext;
-	}
-      if (SegmentNumber != Command->SegmentCount)
-	panic("DAC960: SegmentNumber != SegmentCount\n");
-    }
-  DAC960_QueueCommand(Command);
-  return true;
-}
-
-
-/*
-  DAC960_ProcessRequests attempts to remove as many I/O Requests as possible
-  from Controller's I/O Request Queue and queue them to the Controller.
-*/
-
-static inline void DAC960_ProcessRequests(DAC960_Controller_T *Controller)
-{
-  while (Controller->FreeCommands != NULL)
-    if (!DAC960_ProcessRequest(Controller, NULL)) break;
-}
-
-
-/*
-  DAC960_RequestFunction0 is the I/O Request Function for DAC960 Controller 0.
-*/
-
-static void DAC960_RequestFunction0(void)
-{
-  DAC960_Controller_T *Controller = DAC960_Controllers[0];
-  ProcessorFlags_T ProcessorFlags;
-  /*
-    Acquire exclusive access to Controller.
-  */
-  DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
-  /*
-    Process I/O Requests for Controller.
-   */
-  DAC960_ProcessRequests(Controller);
-  /*
-    Release exclusive access to Controller.
-  */
-  DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
-}
-
-
-/*
-  DAC960_RequestFunction1 is the I/O Request Function for DAC960 Controller 1.
-*/
-
-static void DAC960_RequestFunction1(void)
-{
-  DAC960_Controller_T *Controller = DAC960_Controllers[1];
-  ProcessorFlags_T ProcessorFlags;
-  /*
-    Acquire exclusive access to Controller.
-  */
-  DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
-  /*
-    Process I/O Requests for Controller.
-   */
-  DAC960_ProcessRequests(Controller);
-  /*
-    Release exclusive access to Controller.
-  */
-  DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
-}
-
-
-/*
-  DAC960_RequestFunction2 is the I/O Request Function for DAC960 Controller 2.
-*/
-
-static void DAC960_RequestFunction2(void)
-{
-  DAC960_Controller_T *Controller = DAC960_Controllers[2];
-  ProcessorFlags_T ProcessorFlags;
-  /*
-    Acquire exclusive access to Controller.
-  */
-  DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
-  /*
-    Process I/O Requests for Controller.
-   */
-  DAC960_ProcessRequests(Controller);
-  /*
-    Release exclusive access to Controller.
-  */
-  DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
-}
-
-
-/*
-  DAC960_RequestFunction3 is the I/O Request Function for DAC960 Controller 3.
-*/
-
-static void DAC960_RequestFunction3(void)
-{
-  DAC960_Controller_T *Controller = DAC960_Controllers[3];
-  ProcessorFlags_T ProcessorFlags;
-  /*
-    Acquire exclusive access to Controller.
-  */
-  DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
-  /*
-    Process I/O Requests for Controller.
-   */
-  DAC960_ProcessRequests(Controller);
-  /*
-    Release exclusive access to Controller.
-  */
-  DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
-}
-
-
-/*
-  DAC960_RequestFunction4 is the I/O Request Function for DAC960 Controller 4.
-*/
-
-static void DAC960_RequestFunction4(void)
-{
-  DAC960_Controller_T *Controller = DAC960_Controllers[4];
-  ProcessorFlags_T ProcessorFlags;
-  /*
-    Acquire exclusive access to Controller.
-  */
-  DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
-  /*
-    Process I/O Requests for Controller.
-   */
-  DAC960_ProcessRequests(Controller);
-  /*
-    Release exclusive access to Controller.
-  */
-  DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
-}
-
-
-/*
-  DAC960_RequestFunction5 is the I/O Request Function for DAC960 Controller 5.
-*/
-
-static void DAC960_RequestFunction5(void)
-{
-  DAC960_Controller_T *Controller = DAC960_Controllers[5];
-  ProcessorFlags_T ProcessorFlags;
-  /*
-    Acquire exclusive access to Controller.
-  */
-  DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
-  /*
-    Process I/O Requests for Controller.
-   */
-  DAC960_ProcessRequests(Controller);
-  /*
-    Release exclusive access to Controller.
-  */
-  DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
-}
-
-
-/*
-  DAC960_RequestFunction6 is the I/O Request Function for DAC960 Controller 6.
-*/
-
-static void DAC960_RequestFunction6(void)
-{
-  DAC960_Controller_T *Controller = DAC960_Controllers[6];
-  ProcessorFlags_T ProcessorFlags;
-  /*
-    Acquire exclusive access to Controller.
-  */
-  DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
-  /*
-    Process I/O Requests for Controller.
-   */
-  DAC960_ProcessRequests(Controller);
-  /*
-    Release exclusive access to Controller.
-  */
-  DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
-}
-
-
-/*
-  DAC960_RequestFunction7 is the I/O Request Function for DAC960 Controller 7.
-*/
-
-static void DAC960_RequestFunction7(void)
-{
-  DAC960_Controller_T *Controller = DAC960_Controllers[7];
-  ProcessorFlags_T ProcessorFlags;
-  /*
-    Acquire exclusive access to Controller.
-  */
-  DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
-  /*
-    Process I/O Requests for Controller.
-   */
-  DAC960_ProcessRequests(Controller);
-  /*
-    Release exclusive access to Controller.
-  */
-  DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
-}
-
-
-/*
-  DAC960_ReadWriteError prints an appropriate error message for Command when
-  an error occurs on a read or write operation.
-*/
-
-static void DAC960_ReadWriteError(DAC960_Command_T *Command)
-{
-  DAC960_Controller_T *Controller = Command->Controller;
-  char *CommandName = "UNKNOWN";
-  switch (Command->CommandType)
-    {
-    case DAC960_ReadCommand:
-    case DAC960_ReadRetryCommand:
-      CommandName = "READ";
-      break;
-    case DAC960_WriteCommand:
-    case DAC960_WriteRetryCommand:
-      CommandName = "WRITE";
-      break;
-    case DAC960_MonitoringCommand:
-    case DAC960_ImmediateCommand:
-      break;
-    }
-  switch (Command->CommandStatus)
-    {
-    case DAC960_IrrecoverableDataError:
-      DAC960_Error("Irrecoverable Data Error on %s:\n",
-		   Controller, CommandName);
-      break;
-    case DAC960_LogicalDriveNonexistentOrOffline:
-      break;
-    case DAC960_AccessBeyondEndOfLogicalDrive:
-      DAC960_Error("Attempt to Access Beyond End of Logical Drive "
-		   "on %s:\n", Controller, CommandName);
-      break;
-    case DAC960_BadDataEncountered:
-      DAC960_Error("Bad Data Encountered on %s:\n", Controller, CommandName);
-      break;
-    default:
-      DAC960_Error("Unexpected Error Status %04X on %s:\n",
-		   Controller, Command->CommandStatus, CommandName);
-      break;
-    }
-  DAC960_Error("  /dev/rd/c%dd%d:   absolute blocks %d..%d\n",
-	       Controller, Controller->ControllerNumber,
-	       Command->LogicalDriveNumber, Command->BlockNumber,
-	       Command->BlockNumber + Command->BlockCount - 1);
-  if (DAC960_PartitionNumber(Command->BufferHeader->b_rdev) > 0)
-    DAC960_Error("  /dev/rd/c%dd%dp%d: relative blocks %d..%d\n",
-		 Controller, Controller->ControllerNumber,
-		 Command->LogicalDriveNumber,
-		 DAC960_PartitionNumber(Command->BufferHeader->b_rdev),
-		 Command->BufferHeader->b_rsector,
-		 Command->BufferHeader->b_rsector + Command->BlockCount - 1);
-}
-
-
-/*
-  DAC960_ProcessCompletedBuffer performs completion processing for an
-  individual Buffer.
-*/
-
-static inline void DAC960_ProcessCompletedBuffer(BufferHeader_T *BufferHeader,
-						 boolean SuccessfulIO)
-{
-  mark_buffer_uptodate(BufferHeader, SuccessfulIO);
-  unlock_buffer(BufferHeader);
-}
-
-
-/*
-  DAC960_ProcessCompletedCommand performs completion processing for Command.
-*/
-
-static void DAC960_ProcessCompletedCommand(DAC960_Command_T *Command)
-{
-  DAC960_Controller_T *Controller = Command->Controller;
-  DAC960_CommandType_T CommandType = Command->CommandType;
-  DAC960_CommandStatus_T CommandStatus = Command->CommandStatus;
-  BufferHeader_T *BufferHeader = Command->BufferHeader;
-  if (CommandType == DAC960_ReadCommand ||
-      CommandType == DAC960_WriteCommand)
-    {
-      if (CommandStatus == DAC960_NormalCompletion)
-	{
-	  /*
-	    Perform completion processing for all buffers in this I/O Request.
-	  */
-	  while (BufferHeader != NULL)
-	    {
-	      BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
-	      BufferHeader->b_reqnext = NULL;
-	      DAC960_ProcessCompletedBuffer(BufferHeader, true);
-	      BufferHeader = NextBufferHeader;
-	    }
-	  /*
-	    Wake up requestor for swap file paging requests.
-	  */
-	  if (Command->Semaphore != NULL)
-	    {
-	      up(Command->Semaphore);
-	      Command->Semaphore = NULL;
-	    }
-	}
-      else if ((CommandStatus == DAC960_IrrecoverableDataError ||
-		CommandStatus == DAC960_BadDataEncountered) &&
-	       BufferHeader != NULL &&
-	       BufferHeader->b_reqnext != NULL)
-	{
-	  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-	  if (CommandType == DAC960_ReadCommand)
-	    {
-	      Command->CommandType = DAC960_ReadRetryCommand;
-	      CommandMailbox->Type5.CommandOpcode = DAC960_Read;
-	    }
-	  else
-	    {
-	      Command->CommandType = DAC960_WriteRetryCommand;
-	      CommandMailbox->Type5.CommandOpcode = DAC960_Write;
-	    }
-	  Command->BlockCount = BufferHeader->b_size >> DAC960_BlockSizeBits;
-	  CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
-	  CommandMailbox->Type5.BusAddress =
-	    Virtual_to_Bus(BufferHeader->b_data);
-	  DAC960_QueueCommand(Command);
-	  return;
-	}
-      else
-	{
-	  DAC960_ReadWriteError(Command);
-	  /*
-	    Perform completion processing for all buffers in this I/O Request.
-	  */
-	  while (BufferHeader != NULL)
-	    {
-	      BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
-	      BufferHeader->b_reqnext = NULL;
-	      DAC960_ProcessCompletedBuffer(BufferHeader, false);
-	      BufferHeader = NextBufferHeader;
-	    }
-	  /*
-	    Wake up requestor for swap file paging requests.
-	  */
-	  if (Command->Semaphore != NULL)
-	    {
-	      up(Command->Semaphore);
-	      Command->Semaphore = NULL;
-	    }
-	}
-    }
-  else if (CommandType == DAC960_ReadRetryCommand ||
-	   CommandType == DAC960_WriteRetryCommand)
-    {
-      BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
-      BufferHeader->b_reqnext = NULL;
-      /*
-	Perform completion processing for this single buffer.
-      */
-      if (CommandStatus == DAC960_NormalCompletion)
-	DAC960_ProcessCompletedBuffer(BufferHeader, true);
-      else
-	{
-	  DAC960_ReadWriteError(Command);
-	  DAC960_ProcessCompletedBuffer(BufferHeader, false);
-	}
-      if (NextBufferHeader != NULL)
-	{
-	  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-	  Command->BlockNumber +=
-	    BufferHeader->b_size >> DAC960_BlockSizeBits;
-	  Command->BlockCount =
-	    NextBufferHeader->b_size >> DAC960_BlockSizeBits;
-	  Command->BufferHeader = NextBufferHeader;
-	  CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
-	  CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
-	  CommandMailbox->Type5.BusAddress =
-	    Virtual_to_Bus(NextBufferHeader->b_data);
-	  DAC960_QueueCommand(Command);
-	  return;
-	}
-    }
-  else if (CommandType == DAC960_MonitoringCommand)
-    {
-      DAC960_CommandOpcode_T CommandOpcode =
-	Command->CommandMailbox.Common.CommandOpcode;
-      unsigned int OldCriticalLogicalDriveCount = 0;
-      unsigned int NewCriticalLogicalDriveCount = 0;
-      if (CommandOpcode == DAC960_Enquiry)
-	{
-	  DAC960_Enquiry_T *OldEnquiry =
-	    &Controller->Enquiry[Controller->EnquiryIndex];
-	  DAC960_Enquiry_T *NewEnquiry =
-	    &Controller->Enquiry[Controller->EnquiryIndex ^= 1];
-	  OldCriticalLogicalDriveCount = OldEnquiry->CriticalLogicalDriveCount;
-	  NewCriticalLogicalDriveCount = NewEnquiry->CriticalLogicalDriveCount;
-	  if (NewEnquiry->StatusFlags.DeferredWriteError !=
-	      OldEnquiry->StatusFlags.DeferredWriteError)
-	    DAC960_Critical("Deferred Write Error Flag is now %s\n", Controller,
-			    (NewEnquiry->StatusFlags.DeferredWriteError
-			     ? "TRUE" : "FALSE"));
-	  if ((NewCriticalLogicalDriveCount > 0 ||
-	       NewCriticalLogicalDriveCount != OldCriticalLogicalDriveCount) ||
-	      (NewEnquiry->OfflineLogicalDriveCount > 0 ||
-	       NewEnquiry->OfflineLogicalDriveCount !=
-	       OldEnquiry->OfflineLogicalDriveCount) ||
-	      (NewEnquiry->DeadDriveCount > 0 ||
-	       NewEnquiry->DeadDriveCount !=
-	       OldEnquiry->DeadDriveCount) ||
-	      (NewEnquiry->EventLogSequenceNumber !=
-	       OldEnquiry->EventLogSequenceNumber) ||
-	      (jiffies - Controller->SecondaryMonitoringTime
-		 >= DAC960_SecondaryMonitoringInterval))
-	    {
-	      Controller->NeedLogicalDriveInformation = true;
-	      Controller->NewEventLogSequenceNumber =
-		NewEnquiry->EventLogSequenceNumber;
-	      Controller->NeedDeviceStateInformation = true;
-	      Controller->DeviceStateChannel = 0;
-	      Controller->DeviceStateTargetID = 0;
-	      Controller->SecondaryMonitoringTime = jiffies;
-	    }
-	  if ((NewEnquiry->RebuildCount > 0 &&
-	      jiffies - Controller->RebuildLastReportTime
-		>= DAC960_RebuildStatusReportingInterval) ||
-	      NewEnquiry->RebuildCount != OldEnquiry->RebuildCount)
-	    Controller->NeedRebuildProgress = true;
-	}
-      else if (CommandOpcode == DAC960_GetLogicalDriveInformation)
-	{
-	  int LogicalDriveNumber;
-	  for (LogicalDriveNumber = 0;
-	       LogicalDriveNumber < Controller->LogicalDriveCount;
-	       LogicalDriveNumber++)
-	    {
-	      DAC960_LogicalDriveInformation_T *OldLogicalDriveInformation =
-		&Controller->LogicalDriveInformation
-			     [Controller->LogicalDriveInformationIndex]
-			     [LogicalDriveNumber];
-	      DAC960_LogicalDriveInformation_T *NewLogicalDriveInformation =
-		&Controller->LogicalDriveInformation
-			     [Controller->LogicalDriveInformationIndex ^ 1]
-			     [LogicalDriveNumber];
-	      if (NewLogicalDriveInformation->LogicalDriveState !=
-		  OldLogicalDriveInformation->LogicalDriveState)
-		DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
-				"is now %s\n", Controller,
-				LogicalDriveNumber,
-				Controller->ControllerNumber,
-				LogicalDriveNumber,
-				(NewLogicalDriveInformation->LogicalDriveState
-				 == DAC960_LogicalDrive_Online
-				 ? "ONLINE"
-				 : NewLogicalDriveInformation->LogicalDriveState
-				 == DAC960_LogicalDrive_Critical
-				 ? "CRITICAL" : "OFFLINE"));
-	      if (NewLogicalDriveInformation->WriteBack !=
-		  OldLogicalDriveInformation->WriteBack)
-		DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
-				"is now %s\n", Controller,
-				LogicalDriveNumber,
-				Controller->ControllerNumber,
-				LogicalDriveNumber,
-				(NewLogicalDriveInformation->WriteBack
-				 ? "WRITE BACK" : "WRITE THRU"));
-	    }
-	  Controller->LogicalDriveInformationIndex ^= 1;
-	}
-      else if (CommandOpcode == DAC960_PerformEventLogOperation)
-	{
-	  DAC960_EventLogEntry_T *EventLogEntry = &Controller->EventLogEntry;
-	  if (EventLogEntry->SequenceNumber ==
-	      Controller->OldEventLogSequenceNumber)
-	    {
-	      unsigned char SenseKey = EventLogEntry->SenseKey;
-	      unsigned char AdditionalSenseCode =
-		EventLogEntry->AdditionalSenseCode;
-	      unsigned char AdditionalSenseCodeQualifier =
-		EventLogEntry->AdditionalSenseCodeQualifier;
-	      if (SenseKey == 9 &&
-		  AdditionalSenseCode == 0x80 &&
-		  AdditionalSenseCodeQualifier < DAC960_EventMessagesCount)
-		DAC960_Critical("Physical Drive %d:%d %s\n", Controller,
-				EventLogEntry->Channel,
-				EventLogEntry->TargetID,
-				DAC960_EventMessages[
-				  AdditionalSenseCodeQualifier]);
-	      else if (!((SenseKey == 2 &&
-			  AdditionalSenseCode == 0x04 &&
-			  (AdditionalSenseCodeQualifier == 0x01 ||
-			   AdditionalSenseCodeQualifier == 0x02)) ||
-			 (SenseKey == 6 && AdditionalSenseCode == 0x29)))
-		DAC960_Critical("Physical Drive %d:%d Error Log: "
-				"Sense Key = %d, ASC = %02X, ASCQ = %02X\n",
-				Controller,
-				EventLogEntry->Channel,
-				EventLogEntry->TargetID,
-				SenseKey,
-				AdditionalSenseCode,
-				AdditionalSenseCodeQualifier);
-	    }
-	  Controller->OldEventLogSequenceNumber++;
-	}
-      else if (CommandOpcode == DAC960_GetDeviceState)
-	{
-	  DAC960_DeviceState_T *OldDeviceState =
-	    &Controller->DeviceState[Controller->DeviceStateIndex]
-				    [Controller->DeviceStateChannel]
-				    [Controller->DeviceStateTargetID];
-	  DAC960_DeviceState_T *NewDeviceState =
-	    &Controller->DeviceState[Controller->DeviceStateIndex ^ 1]
-				    [Controller->DeviceStateChannel]
-				    [Controller->DeviceStateTargetID];
-	  if (NewDeviceState->DeviceState != OldDeviceState->DeviceState)
-	    DAC960_Critical("Physical Drive %d:%d is now %s\n", Controller,
-			    Controller->DeviceStateChannel,
-			    Controller->DeviceStateTargetID,
-			    (NewDeviceState->DeviceState == DAC960_Device_Dead
-			     ? "DEAD"
-			     : NewDeviceState->DeviceState
-			       == DAC960_Device_WriteOnly
-			       ? "WRITE-ONLY"
-			       : NewDeviceState->DeviceState
-				 == DAC960_Device_Online
-				 ? "ONLINE" : "STANDBY"));
-	  if (++Controller->DeviceStateTargetID == DAC960_MaxTargets)
-	    {
-	      Controller->DeviceStateChannel++;
-	      Controller->DeviceStateTargetID = 0;
-	    }
-	}
-      else if (CommandOpcode == DAC960_GetRebuildProgress)
-	{
-	  unsigned int LogicalDriveNumber =
-	    Controller->RebuildProgress.LogicalDriveNumber;
-	  unsigned int LogicalDriveSize =
-	    Controller->RebuildProgress.LogicalDriveSize;
-	  unsigned int BlocksCompleted =
-	    LogicalDriveSize - Controller->RebuildProgress.RemainingBlocks;
-	  switch (CommandStatus)
-	    {
-	    case DAC960_NormalCompletion:
-	      DAC960_Critical("REBUILD IN PROGRESS: "
-			      "Logical Drive %d (/dev/rd/c%dd%d) "
-			      "%d%% completed\n",
-			      Controller, LogicalDriveNumber,
-			      Controller->ControllerNumber,
-			      LogicalDriveNumber,
-			      (100 * (BlocksCompleted >> 7))
-			      / (LogicalDriveSize >> 7));
-	      break;
-	    case DAC960_RebuildFailed_LogicalDriveFailure:
-	      DAC960_Critical("REBUILD FAILED due to "
-			      "LOGICAL DRIVE FAILURE\n", Controller);
-	      break;
-	    case DAC960_RebuildFailed_BadBlocksOnOther:
-	      DAC960_Critical("REBUILD FAILED due to "
-			      "BAD BLOCKS ON OTHER DRIVES\n", Controller);
-	      break;
-	    case DAC960_RebuildFailed_NewDriveFailed:
-	      DAC960_Critical("REBUILD FAILED due to "
-			      "FAILURE OF DRIVE BEING REBUILT\n", Controller);
-	      break;
-	    case DAC960_RebuildSuccessful:
-	      DAC960_Critical("REBUILD COMPLETED SUCCESSFULLY\n", Controller);
-	      break;
-	    case DAC960_NoRebuildOrCheckInProgress:
-	      break;
-	    }
-	  Controller->RebuildLastReportTime = jiffies;
-	}
-      if (Controller->NeedLogicalDriveInformation &&
-	  NewCriticalLogicalDriveCount >= OldCriticalLogicalDriveCount)
-	{
-	  Controller->NeedLogicalDriveInformation = false;
-	  Command->CommandMailbox.Type3.CommandOpcode =
-	    DAC960_GetLogicalDriveInformation;
-	  Command->CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(
-	      &Controller->LogicalDriveInformation
-			   [Controller->LogicalDriveInformationIndex ^ 1]);
-	  DAC960_QueueCommand(Command);
-	  return;
-	}
-      if (Controller->NewEventLogSequenceNumber
-	  - Controller->OldEventLogSequenceNumber > 0)
-	{
-	  Command->CommandMailbox.Type3E.CommandOpcode =
-	    DAC960_PerformEventLogOperation;
-	  Command->CommandMailbox.Type3E.OperationType =
-	    DAC960_GetEventLogEntry;
-	  Command->CommandMailbox.Type3E.OperationQualifier = 1;
-	  Command->CommandMailbox.Type3E.SequenceNumber =
-	    Controller->OldEventLogSequenceNumber;
-	  Command->CommandMailbox.Type3E.BusAddress =
-	    Virtual_to_Bus(&Controller->EventLogEntry);
-	  DAC960_QueueCommand(Command);
-	  return;
-	}
-      if (Controller->NeedDeviceStateInformation)
-	{
-	  while (Controller->DeviceStateChannel < Controller->Channels)
-	    {
-	      DAC960_DeviceState_T *OldDeviceState =
-		&Controller->DeviceState[Controller->DeviceStateIndex]
-					[Controller->DeviceStateChannel]
-					[Controller->DeviceStateTargetID];
-	      if (OldDeviceState->Present &&
-		  OldDeviceState->DeviceType == DAC960_DiskType)
-		{
-		  Command->CommandMailbox.Type3D.CommandOpcode =
-		    DAC960_GetDeviceState;
-		  Command->CommandMailbox.Type3D.Channel =
-		    Controller->DeviceStateChannel;
-		  Command->CommandMailbox.Type3D.TargetID =
-		    Controller->DeviceStateTargetID;
-		  Command->CommandMailbox.Type3D.BusAddress =
-		    Virtual_to_Bus(&Controller->DeviceState
-				      [Controller->DeviceStateIndex ^ 1]
-				      [Controller->DeviceStateChannel]
-				      [Controller->DeviceStateTargetID]);
-		  DAC960_QueueCommand(Command);
-		  return;
-		}
-	      if (++Controller->DeviceStateTargetID == DAC960_MaxTargets)
-		{
-		  Controller->DeviceStateChannel++;
-		  Controller->DeviceStateTargetID = 0;
-		}
-	    }
-	  Controller->NeedDeviceStateInformation = false;
-	  Controller->DeviceStateIndex ^= 1;
-	}
-      if (Controller->NeedRebuildProgress)
-	{
-	  Controller->NeedRebuildProgress = false;
-	  Command->CommandMailbox.Type3.CommandOpcode =
-	    DAC960_GetRebuildProgress;
-	  Command->CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(&Controller->RebuildProgress);
-	  DAC960_QueueCommand(Command);
-	  return;
-	}
-      if (Controller->NeedLogicalDriveInformation &&
-	  NewCriticalLogicalDriveCount < OldCriticalLogicalDriveCount)
-	{
-	  Controller->NeedLogicalDriveInformation = false;
-	  Command->CommandMailbox.Type3.CommandOpcode =
-	    DAC960_GetLogicalDriveInformation;
-	  Command->CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(
-	      &Controller->LogicalDriveInformation
-			   [Controller->LogicalDriveInformationIndex ^ 1]);
-	  DAC960_QueueCommand(Command);
-	  return;
-	}
-      Controller->MonitoringTimer.expires =
-	jiffies + DAC960_MonitoringTimerInterval;
-      add_timer(&Controller->MonitoringTimer);
-    }
-  else if (CommandType == DAC960_ImmediateCommand)
-    {
-      up(Command->Semaphore);
-      Command->Semaphore = NULL;
-      return;
-    }
-  else panic("DAC960: Unknown Command Type %d\n", CommandType);
-  /*
-    Queue a Monitoring Command to the Controller using the just completed
-    Command if one was deferred previously due to lack of a free Command when
-    the Monitoring Timer Function was called.
-  */
-  if (Controller->MonitoringCommandDeferred)
-    {
-      Controller->MonitoringCommandDeferred = false;
-      DAC960_QueueMonitoringCommand(Command);
-      return;
-    }
-  /*
-    Attempt to remove a new I/O Request from the Controller's I/O Request
-    Queue and queue it to the Controller using the just completed Command.
-    If there is no I/O Request to be queued, deallocate the Command.
-  */
-  if (!DAC960_ProcessRequest(Controller, Command))
-    DAC960_DeallocateCommand(Command);
-}
-
-
-/*
-  DAC960_InterruptHandler handles hardware interrupts from DAC960 Controllers.
-*/
-
-static void DAC960_InterruptHandler(int IRQ_Channel,
-				    void *DeviceIdentifier,
-				    Registers_T *InterruptRegisters)
-{
-  DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
-  void *ControllerBaseAddress = Controller->BaseAddress;
-  DAC960_V4_StatusMailbox_T *NextStatusMailbox;
-  ProcessorFlags_T ProcessorFlags;
-  /*
-    Acquire exclusive access to Controller.
-  */
-  DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
-  /*
-    Process Hardware Interrupts for Controller.
-  */
-  switch (Controller->ControllerType)
-    {
-    case DAC960_V4_Controller:
-      DAC960_V4_AcknowledgeInterrupt(ControllerBaseAddress);
-      NextStatusMailbox = Controller->NextStatusMailbox;
-      while (NextStatusMailbox->Fields.Valid)
-	{
-	  DAC960_CommandIdentifier_T CommandIdentifier =
-	    NextStatusMailbox->Fields.CommandIdentifier;
-	  DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier];
-	  Command->CommandStatus = NextStatusMailbox->Fields.CommandStatus;
-	  NextStatusMailbox->Word = 0;
-	  if (++NextStatusMailbox > Controller->LastStatusMailbox)
-	    NextStatusMailbox = Controller->FirstStatusMailbox;
-	  DAC960_ProcessCompletedCommand(Command);
-	}
-      Controller->NextStatusMailbox = NextStatusMailbox;
-      break;
-    case DAC960_V3_Controller:
-      while (DAC960_V3_StatusAvailableP(ControllerBaseAddress))
-	{
-	  DAC960_CommandIdentifier_T CommandIdentifier =
-	    DAC960_V3_ReadStatusCommandIdentifier(ControllerBaseAddress);
-	  DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier];
-	  Command->CommandStatus =
-	    DAC960_V3_ReadStatusRegister(ControllerBaseAddress);
-	  DAC960_V3_AcknowledgeInterrupt(ControllerBaseAddress);
-	  DAC960_V3_AcknowledgeStatus(ControllerBaseAddress);
-	  DAC960_ProcessCompletedCommand(Command);
-	}
-      break;
-    }
-  /*
-    Attempt to remove additional I/O Requests from the Controller's
-    I/O Request Queue and queue them to the Controller.
-  */
-  DAC960_ProcessRequests(Controller);
-  /*
-    Release exclusive access to Controller.
-  */
-  DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
-}
-
-
-/*
-  DAC960_QueueMonitoringCommand queues a Monitoring Command to Controller.
-*/
-
-static void DAC960_QueueMonitoringCommand(DAC960_Command_T *Command)
-{
-  DAC960_Controller_T *Controller = Command->Controller;
-  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-  DAC960_ClearCommand(Command);
-  Command->CommandType = DAC960_MonitoringCommand;
-  CommandMailbox->Type3.CommandOpcode = DAC960_Enquiry;
-  CommandMailbox->Type3.BusAddress =
-    Virtual_to_Bus(&Controller->Enquiry[Controller->EnquiryIndex ^ 1]);
-  DAC960_QueueCommand(Command);
-}
-
-
-/*
-  DAC960_MonitoringTimerFunction is the timer function for monitoring
-  the status of DAC960 Controllers.
-*/
-
-static void DAC960_MonitoringTimerFunction(unsigned long TimerData)
-{
-  DAC960_Controller_T *Controller = (DAC960_Controller_T *) TimerData;
-  DAC960_Command_T *Command;
-  ProcessorFlags_T ProcessorFlags;
-  /*
-    Acquire exclusive access to Controller.
-  */
-  DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
-  /*
-    Queue a Status Monitoring Command for Controller;
-  */
-  Command = DAC960_AllocateCommand(Controller);
-  if (Command != NULL)
-    DAC960_QueueMonitoringCommand(Command);
-  else Controller->MonitoringCommandDeferred = true;
-  /*
-    Release exclusive access to Controller.
-  */
-  DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
-}
-
-
-/*
-  DAC960_Open is the Device Open Function for the DAC960 Driver.
-*/
-
-static int DAC960_Open(Inode_T *Inode, File_T *File)
-{
-  int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev);
-  int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev);
-  DAC960_Controller_T *Controller;
-  if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1)
-    return -ENXIO;
-  Controller = DAC960_Controllers[ControllerNumber];
-  if (Controller == NULL ||
-      LogicalDriveNumber > Controller->LogicalDriveCount - 1)
-    return -ENXIO;
-  if (Controller->LogicalDriveInformation
-		  [Controller->LogicalDriveInformationIndex]
-		  [LogicalDriveNumber] .LogicalDriveState
-      == DAC960_LogicalDrive_Offline)
-    return -ENXIO;
-  if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0)
-    return -ENXIO;
-  /*
-    Increment Controller and Logical Drive Usage Counts.
-  */
-  Controller->ControllerUsageCount++;
-  Controller->LogicalDriveUsageCount[LogicalDriveNumber]++;
-  return 0;
-}
-
-
-/*
-  DAC960_Release is the Device Release Function for the DAC960 Driver.
-*/
-
-static void DAC960_Release(Inode_T *Inode, File_T *File)
-{
-  int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev);
-  int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev);
-  DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
-  /*
-    Force any buffered data to be written.
-  */
-  fsync_dev(Inode->i_rdev);
-  /*
-    Decrement the Logical Drive and Controller Usage Counts.
-  */
-  Controller->LogicalDriveUsageCount[LogicalDriveNumber]--;
-  Controller->ControllerUsageCount--;
-}
-
-
-/*
-  DAC960_Ioctl is the Device Ioctl Function for the DAC960 Driver.
-*/
-
-static int DAC960_Ioctl(Inode_T *Inode, File_T *File,
-			unsigned int Request, unsigned long Argument)
-{
-  int ControllerNumber = DAC960_ControllerNumber(Inode->i_rdev);
-  int LogicalDriveNumber = DAC960_LogicalDriveNumber(Inode->i_rdev);
-  int PartitionNumber, ErrorCode;
-  unsigned short Cylinders;
-  DiskGeometry_T *Geometry;
-  DAC960_Controller_T *Controller;
-  if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1)
-    return -ENXIO;
-  Controller = DAC960_Controllers[ControllerNumber];
-  if (Controller == NULL ||
-      LogicalDriveNumber > Controller->LogicalDriveCount - 1)
-    return -ENXIO;
-  switch (Request)
-    {
-    case HDIO_GETGEO:
-      /* Get BIOS Disk Geometry. */
-      Geometry = (DiskGeometry_T *) Argument;
-      if (Geometry == NULL) return -EINVAL;
-      ErrorCode = verify_area(VERIFY_WRITE, Geometry, sizeof(DiskGeometry_T));
-      if (ErrorCode != 0) return ErrorCode;
-      Cylinders =
-	Controller->LogicalDriveInformation
-		    [Controller->LogicalDriveInformationIndex]
-		    [LogicalDriveNumber].LogicalDriveSize
-	/ (Controller->GeometryTranslationHeads *
-	   Controller->GeometryTranslationSectors);
-      put_user(Controller->GeometryTranslationHeads, &Geometry->heads);
-      put_user(Controller->GeometryTranslationSectors, &Geometry->sectors);
-      put_user(Cylinders, &Geometry->cylinders);
-      put_user(Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)]
-					  .start_sect, &Geometry->start);
-      return 0;
-    case BLKGETSIZE:
-      /* Get Device Size. */
-      if ((long *) Argument == NULL) return -EINVAL;
-      ErrorCode = verify_area(VERIFY_WRITE, (long *) Argument, sizeof(long));
-      if (ErrorCode != 0) return ErrorCode;
-      put_user(Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)].nr_sects,
-	       (long *) Argument);
-      return 0;
-    case BLKRAGET:
-      /* Get Read-Ahead. */
-      if ((int *) Argument == NULL) return -EINVAL;
-      ErrorCode = verify_area(VERIFY_WRITE, (int *) Argument, sizeof(int));
-      if (ErrorCode != 0) return ErrorCode;
-      put_user(read_ahead[MAJOR(Inode->i_rdev)], (int *) Argument);
-      return 0;
-    case BLKRASET:
-      /* Set Read-Ahead. */
-      if (!suser()) return -EACCES;
-      if (Argument > 256) return -EINVAL;
-      read_ahead[MAJOR(Inode->i_rdev)] = Argument;
-      return 0;
-    case BLKFLSBUF:
-      /* Flush Buffers. */
-      if (!suser()) return -EACCES;
-      fsync_dev(Inode->i_rdev);
-      invalidate_buffers(Inode->i_rdev);
-      return 0;
-    case BLKRRPART:
-      /* Re-Read Partition Table. */
-      if (!suser()) return -EACCES;
-      if (Controller->LogicalDriveUsageCount[LogicalDriveNumber] > 1)
-	return -EBUSY;
-      for (PartitionNumber = 0;
-	   PartitionNumber < DAC960_MaxPartitions;
-	   PartitionNumber++)
-	{
-	  KernelDevice_T Device = DAC960_KernelDevice(ControllerNumber,
-						      LogicalDriveNumber,
-						      PartitionNumber);
-	  int MinorNumber = DAC960_MinorNumber(LogicalDriveNumber,
-					       PartitionNumber);
-	  if (Controller->GenericDiskInfo.part[MinorNumber].nr_sects == 0)
-	    continue;
-	  /*
-	    Flush all changes and invalidate buffered state.
-	  */
-	  sync_dev(Device);
-	  invalidate_inodes(Device);
-	  invalidate_buffers(Device);
-	  /*
-	    Clear existing partition sizes.
-	  */
-	  if (PartitionNumber > 0)
-	    {
-	      Controller->GenericDiskInfo.part[MinorNumber].start_sect = 0;
-	      Controller->GenericDiskInfo.part[MinorNumber].nr_sects = 0;
-	    }
-	  /*
-	    Reset the Block Size so that the partition table can be read.
-	  */
-	  set_blocksize(Device, BLOCK_SIZE);
-	}
-      resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber);
-      return 0;
-    }
-  return -EINVAL;
-}
-
-
-/*
-  DAC960_GenericDiskInit is the Generic Disk Information Initialization
-  Function for the DAC960 Driver.
-*/
-
-static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo)
-{
-  DAC960_Controller_T *Controller =
-    (DAC960_Controller_T *) GenericDiskInfo->real_devices;
-  DAC960_LogicalDriveInformation_T *LogicalDriveInformation =
-    Controller->LogicalDriveInformation
-		[Controller->LogicalDriveInformationIndex];
-  int LogicalDriveNumber;
-  for (LogicalDriveNumber = 0;
-       LogicalDriveNumber < Controller->LogicalDriveCount;
-       LogicalDriveNumber++)
-    GenericDiskInfo->part[DAC960_MinorNumber(LogicalDriveNumber, 0)].nr_sects =
-      LogicalDriveInformation[LogicalDriveNumber].LogicalDriveSize;
-}
-
-
-/*
-  DAC960_Message prints Driver Messages.
-*/
-
-static void DAC960_Message(DAC960_MessageLevel_T MessageLevel,
-			   char *Format,
-			   DAC960_Controller_T *Controller,
-			   ...)
-{
-  static char Buffer[DAC960_LineBufferSize];
-  static boolean BeginningOfLine = true;
-  va_list Arguments;
-  int Length = 0;
-  va_start(Arguments, Controller);
-  Length = vsprintf(Buffer, Format, Arguments);
-  va_end(Arguments);
-  if (MessageLevel == DAC960_AnnounceLevel)
-    {
-      static int AnnouncementLines = 0;
-      strcpy(&Controller->MessageBuffer[Controller->MessageBufferLength],
-	     Buffer);
-      Controller->MessageBufferLength += Length;
-      if (++AnnouncementLines <= 2)
-	printk("%sDAC960: %s", DAC960_MessageLevelMap[MessageLevel], Buffer);
-    }
-  else if (MessageLevel == DAC960_InfoLevel)
-    {
-      strcpy(&Controller->MessageBuffer[Controller->MessageBufferLength],
-	     Buffer);
-      Controller->MessageBufferLength += Length;
-      if (BeginningOfLine)
-	{
-	  if (Buffer[0] != '\n' || Length > 1)
-	    printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
-		   Controller->ControllerNumber, Buffer);
-	}
-      else printk("%s", Buffer);
-    }
-  else
-    {
-      if (BeginningOfLine)
-	printk("%sDAC960#%d: %s", DAC960_MessageLevelMap[MessageLevel],
-	       Controller->ControllerNumber, Buffer);
-      else printk("%s", Buffer);
-    }
-  BeginningOfLine = (Buffer[Length-1] == '\n');
-}
diff -urN linux-2.0.37-pre3/drivers/scsi/DAC960.h linux-2.0.37-pre4/drivers/scsi/DAC960.h
--- linux-2.0.37-pre3/drivers/scsi/DAC960.h	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/scsi/DAC960.h	1969-12-31 16:00:00.000000000 -0800
@@ -1,1565 +0,0 @@
-/*
-
-  Linux Driver for Mylex DAC960 PCI RAID Controllers
-
-  Copyright 1998 by Leonard N. Zubkoff <lnz@dandelion.com>
-
-  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.
-
-  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.
-
-*/
-
-
-/*
-  DAC960_DriverVersion protects the private portion of this file.
-*/
-
-#ifdef DAC960_DriverVersion
-
-
-/*
-  Define the maximum number of DAC960 Controllers supported by this driver.
-*/
-
-#define DAC960_MaxControllers			8
-
-
-/*
-  Define the maximum number of Controller Channels supported by this driver.
-*/
-
-#define DAC960_MaxChannels			3
-
-
-/*
-  Define the maximum number of Targets per Channel supported by this driver.
-*/
-
-#define DAC960_MaxTargets			16
-
-
-/*
-  Define the maximum number of Logical Drives supported by any DAC960 model.
-*/
-
-#define DAC960_MaxLogicalDrives			32
-
-
-/*
-  Define the maximum number of Partitions allowed for each Logical Drive.
-*/
-
-#define DAC960_MaxPartitions			8
-#define DAC960_MaxPartitionsBits		3
-
-
-/*
-  Define the maximum Driver Queue Depth and Controller Queue Depth supported
-  by any DAC960 model.
-*/
-
-#define DAC960_MaxDriverQueueDepth		127
-#define DAC960_MaxControllerQueueDepth		128
-
-
-/*
-  Define the maximum number of Scatter/Gather Segments supported by any
-  DAC960 model.
-*/
-
-#define DAC960_MaxScatterGatherSegments		33
-
-
-/*
-  Define the DAC960 Controller Monitoring Timer Interval.
-*/
-
-#define DAC960_MonitoringTimerInterval		(7 * HZ)
-
-
-/*
-  Define the DAC960 Controller Secondary Monitoring Interval.
-*/
-
-#define DAC960_SecondaryMonitoringInterval	(60 * HZ)
-
-
-/*
-  Define the DAC960 Controller Rebuild Status Reporting Interval.
-*/
-
-#define DAC960_RebuildStatusReportingInterval	(60 * HZ)
-
-
-/*
-  Define the number of Command Mailboxes and Status Mailboxes used by the
-  V4 Memory Mailbox Interface.
-*/
-
-#define DAC960_CommandMailboxCount		256
-#define DAC960_StatusMailboxCount		1024
-
-
-/*
-  Define macros to extract the Controller Number, Logical Drive Number, and
-  Partition Number from a Kernel Device, and to construct a Major Number, Minor
-  Number, and Kernel Device from the Controller Number, Logical Drive Number,
-  and Partition Number.  There is one Major Number assigned to each Controller.
-  The associated Minor Number is divided into the Logical Drive Number and
-  Partition Number.
-*/
-
-#define DAC960_ControllerNumber(Device) \
-  (MAJOR(Device) - DAC960_MAJOR)
-
-#define DAC960_LogicalDriveNumber(Device) \
-  (MINOR(Device) >> DAC960_MaxPartitionsBits)
-
-#define DAC960_PartitionNumber(Device) \
-  (MINOR(Device) & (DAC960_MaxPartitions - 1))
-
-#define DAC960_MajorNumber(ControllerNumber) \
-  (DAC960_MAJOR + (ControllerNumber))
-
-#define DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber) \
-   (((LogicalDriveNumber) << DAC960_MaxPartitionsBits) | (PartitionNumber))
-
-#define DAC960_MinorCount			(DAC960_MaxLogicalDrives \
-						 * DAC960_MaxPartitions)
-
-#define DAC960_KernelDevice(ControllerNumber,				       \
-			    LogicalDriveNumber,				       \
-			    PartitionNumber)				       \
-   MKDEV(DAC960_MajorNumber(ControllerNumber),				       \
-	 DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber))
-
-
-/*
-  Define the DAC960 Controller fixed Block Size and Block Size Bits.
-*/
-
-#define DAC960_BlockSize			512
-#define DAC960_BlockSizeBits			9
-
-
-/*
-  Define the Controller Line and Message Buffer Sizes.
-*/
-
-#define DAC960_LineBufferSize			100
-#define DAC960_MessageBufferSize		2048
-
-
-/*
-  Define the Driver Message Levels.
-*/
-
-typedef enum DAC960_MessageLevel
-{
-  DAC960_AnnounceLevel =			0,
-  DAC960_InfoLevel =				1,
-  DAC960_NoticeLevel =				2,
-  DAC960_WarningLevel =				3,
-  DAC960_ErrorLevel =				4,
-  DAC960_CriticalLevel =			5
-}
-DAC960_MessageLevel_T;
-
-static char
-  *DAC960_MessageLevelMap[] =
-    { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE,
-      KERN_WARNING, KERN_ERR, KERN_CRIT };
-
-
-/*
-  Define Driver Message macros.
-*/
-
-#define DAC960_Announce(Format, Arguments...) \
-  DAC960_Message(DAC960_AnnounceLevel, Format, ##Arguments)
-
-#define DAC960_Info(Format, Arguments...) \
-  DAC960_Message(DAC960_InfoLevel, Format, ##Arguments)
-
-#define DAC960_Notice(Format, Arguments...) \
-  DAC960_Message(DAC960_NoticeLevel, Format, ##Arguments)
-
-#define DAC960_Warning(Format, Arguments...) \
-  DAC960_Message(DAC960_WarningLevel, Format, ##Arguments)
-
-#define DAC960_Error(Format, Arguments...) \
-  DAC960_Message(DAC960_ErrorLevel, Format, ##Arguments)
-
-#define DAC960_Critical(Format, Arguments...) \
-  DAC960_Message(DAC960_CriticalLevel, Format, ##Arguments)
-
-
-/*
-  Define the types of DAC960 Controllers that are supported.
-*/
-
-typedef enum
-{
-  DAC960_V4_Controller =			1,	/* DAC960PTL/PJ/PG */
-  DAC960_V3_Controller =			2	/* DAC960PU/PD/PL */
-}
-DAC960_ControllerType_T;
-
-
-/*
-  Define a Boolean data type.
-*/
-
-typedef enum { false, true } __attribute__ ((packed)) boolean;
-
-
-/*
-  Define a 32 bit I/O Address data type.
-*/
-
-typedef unsigned int DAC960_IO_Address_T;
-
-
-/*
-  Define a 32 bit PCI Bus Address data type.
-*/
-
-typedef unsigned int DAC960_PCI_Address_T;
-
-
-/*
-  Define a 32 bit Bus Address data type.
-*/
-
-typedef unsigned int DAC960_BusAddress_T;
-
-
-/*
-  Define a 32 bit Byte Count data type.
-*/
-
-typedef unsigned int DAC960_ByteCount_T;
-
-
-/*
-  Define types for some of the structures that interface with the rest
-  of the Linux Kernel and I/O Subsystem.
-*/
-
-typedef struct buffer_head BufferHeader_T;
-typedef struct file File_T;
-typedef struct file_operations FileOperations_T;
-typedef struct gendisk GenericDiskInfo_T;
-typedef struct hd_geometry DiskGeometry_T;
-typedef struct hd_struct DiskPartition_T;
-typedef struct inode Inode_T;
-typedef kdev_t KernelDevice_T;
-typedef unsigned long ProcessorFlags_T;
-typedef struct pt_regs Registers_T;
-typedef struct request IO_Request_T;
-typedef struct semaphore Semaphore_T;
-typedef struct timer_list Timer_T;
-
-
-/*
-  Define the DAC960 V4 Controller Interface Register Offsets.
-*/
-
-#define DAC960_V4_RegisterWindowSize		0x2000
-
-typedef enum
-{
-  DAC960_V4_InboundDoorBellRegisterOffset =	0x0020,
-  DAC960_V4_OutboundDoorBellRegisterOffset =	0x002C,
-  DAC960_V4_InterruptMaskRegisterOffset =	0x0034,
-  DAC960_V4_CommandOpcodeRegisterOffset =	0x1000,
-  DAC960_V4_CommandIdentifierRegisterOffset =	0x1001,
-  DAC960_V4_MailboxRegister2Offset =		0x1002,
-  DAC960_V4_MailboxRegister3Offset =		0x1003,
-  DAC960_V4_MailboxRegister4Offset =		0x1004,
-  DAC960_V4_MailboxRegister5Offset =		0x1005,
-  DAC960_V4_MailboxRegister6Offset =		0x1006,
-  DAC960_V4_MailboxRegister7Offset =		0x1007,
-  DAC960_V4_MailboxRegister8Offset =		0x1008,
-  DAC960_V4_MailboxRegister9Offset =		0x1009,
-  DAC960_V4_MailboxRegister10Offset =		0x100A,
-  DAC960_V4_MailboxRegister11Offset =		0x100B,
-  DAC960_V4_MailboxRegister12Offset =		0x100C,
-  DAC960_V4_StatusCommandIdentifierRegOffset =	0x1018,
-  DAC960_V4_StatusRegisterOffset =		0x101A
-}
-DAC960_V4_RegisterOffsets_T;
-
-
-/*
-  Define the structure of the DAC960 V4 Inbound Door Bell Register.
-*/
-
-typedef union DAC960_V4_InboundDoorBellRegister
-{
-  unsigned int All;
-  struct {
-    boolean NewCommand:1;				/* Bit 0 */
-    boolean AcknowledgeStatus:1;			/* Bit 1 */
-    boolean SoftReset:1;				/* Bit 2 */
-    unsigned int :29;					/* Bits 3-31 */
-  } Write;
-  struct {
-    boolean MailboxFull:1;				/* Bit 0 */
-    unsigned int :31;					/* Bits 1-31 */
-  } Read;
-}
-DAC960_V4_InboundDoorBellRegister_T;
-
-
-/*
-  Define the structure of the DAC960 V4 Outbound Door Bell Register.
-*/
-
-typedef union DAC960_V4_OutboundDoorBellRegister
-{
-  unsigned int All;
-  struct {
-    boolean AcknowledgeInterrupt:1;			/* Bit 0 */
-    unsigned int :31;					/* Bits 1-31 */
-  } Write;
-  struct {
-    boolean StatusAvailable:1;				/* Bit 0 */
-    unsigned int :31;					/* Bits 1-31 */
-  } Read;
-}
-DAC960_V4_OutboundDoorBellRegister_T;
-
-
-/*
-  Define the structure of the DAC960 V4 Interrupt Mask Register.
-*/
-
-typedef union DAC960_V4_InterruptMaskRegister
-{
-  unsigned int All;
-  struct {
-    unsigned int MessageUnitInterruptMask1:2;		/* Bits 0-1 */
-    boolean DisableInterrupts:1;			/* Bit 2 */
-    unsigned int MessageUnitInterruptMask2:5;		/* Bits 3-7 */
-    unsigned int Reserved0:24;				/* Bits 8-31 */
-  } Bits;
-}
-DAC960_V4_InterruptMaskRegister_T;
-
-
-/*
-  Define the DAC960 V3 Controller Interface Register Offsets.
-*/
-
-#define DAC960_V3_RegisterWindowSize		0x80
-
-typedef enum
-{
-  DAC960_V3_CommandOpcodeRegisterOffset =	0x00,
-  DAC960_V3_CommandIdentifierRegisterOffset =	0x01,
-  DAC960_V3_MailboxRegister2Offset =		0x02,
-  DAC960_V3_MailboxRegister3Offset =		0x03,
-  DAC960_V3_MailboxRegister4Offset =		0x04,
-  DAC960_V3_MailboxRegister5Offset =		0x05,
-  DAC960_V3_MailboxRegister6Offset =		0x06,
-  DAC960_V3_MailboxRegister7Offset =		0x07,
-  DAC960_V3_MailboxRegister8Offset =		0x08,
-  DAC960_V3_MailboxRegister9Offset =		0x09,
-  DAC960_V3_MailboxRegister10Offset =		0x0A,
-  DAC960_V3_MailboxRegister11Offset =		0x0B,
-  DAC960_V3_MailboxRegister12Offset =		0x0C,
-  DAC960_V3_StatusCommandIdentifierRegOffset =	0x0D,
-  DAC960_V3_StatusRegisterOffset =		0x0E,
-  DAC960_V3_InboundDoorBellRegisterOffset =	0x40,
-  DAC960_V3_OutboundDoorBellRegisterOffset =	0x41,
-  DAC960_V3_InterruptEnableRegisterOffset =	0x43
-}
-DAC960_V3_RegisterOffsets_T;
-
-
-/*
-  Define the structure of the DAC960 V3 Inbound Door Bell Register.
-*/
-
-typedef union DAC960_V3_InboundDoorBellRegister
-{
-  unsigned char All;
-  struct {
-    boolean NewCommand:1;				/* Bit 0 */
-    boolean AcknowledgeStatus:1;			/* Bit 1 */
-    unsigned char :1;					/* Bit 2 */
-    boolean SoftReset:1;				/* Bit 3 */
-    unsigned char :4;					/* Bits 4-7 */
-  } Write;
-  struct {
-    boolean MailboxFull:1;				/* Bit 0 */
-    unsigned char :7;					/* Bits 1-7 */
-  } Read;
-}
-DAC960_V3_InboundDoorBellRegister_T;
-
-
-/*
-  Define the structure of the DAC960 V3 Outbound Door Bell Register.
-*/
-
-typedef union DAC960_V3_OutboundDoorBellRegister
-{
-  unsigned char All;
-  struct {
-    boolean AcknowledgeInterrupt:1;			/* Bit 0 */
-    unsigned char :7;					/* Bits 1-7 */
-  } Write;
-  struct {
-    boolean StatusAvailable:1;				/* Bit 0 */
-    unsigned char :7;					/* Bits 1-7 */
-  } Read;
-}
-DAC960_V3_OutboundDoorBellRegister_T;
-
-
-/*
-  Define the structure of the DAC960 V3 Interrupt Enable Register.
-*/
-
-typedef union DAC960_V3_InterruptEnableRegister
-{
-  unsigned char All;
-  struct {
-    boolean EnableInterrupts:1;				/* Bit 0 */
-    unsigned char :7;					/* Bits 1-7 */
-  } Bits;
-}
-DAC960_V3_InterruptEnableRegister_T;
-
-
-/*
-  Define the DAC960 Command Identifier type.
-*/
-
-typedef unsigned char DAC960_CommandIdentifier_T;
-
-
-/*
-  Define the DAC960 Command Opcodes.
-*/
-
-typedef enum
-{
-  /* I/O Commands */
-  DAC960_ReadExtended =				0x33,
-  DAC960_WriteExtended =			0x34,
-  DAC960_ReadAheadExtended =			0x35,
-  DAC960_ReadExtendedWithScatterGather =	0xB3,
-  DAC960_WriteExtendedWithScatterGather =	0xB4,
-  DAC960_Read =					0x36,
-  DAC960_ReadWithOldScatterGather =		0xB6,
-  DAC960_Write =				0x37,
-  DAC960_WriteWithOldScatterGather =		0xB7,
-  DAC960_DCDB =					0x04,
-  DAC960_DCDBWithScatterGather =		0x84,
-  DAC960_Flush =				0x0A,
-  /* Controller Status Related Commands */
-  DAC960_Enquiry =				0x53,
-  DAC960_Enquiry2 =				0x1C,
-  DAC960_GetLogicalDriveElement =		0x55,
-  DAC960_GetLogicalDriveInformation =		0x19,
-  DAC960_IOPortRead =				0x39,
-  DAC960_IOPortWrite =				0x3A,
-  DAC960_GetSDStats =				0x3E,
-  DAC960_GetPDStats =				0x3F,
-  DAC960_PerformEventLogOperation =		0x72,
-  /* Device Related Commands */
-  DAC960_StartDevice =				0x10,
-  DAC960_GetDeviceState =			0x50,
-  DAC960_StopChannel =				0x13,
-  DAC960_StartChannel =				0x12,
-  DAC960_ResetChannel =				0x1A,
-  /* Commands Associated with Data Consistency and Errors */
-  DAC960_Rebuild =				0x09,
-  DAC960_RebuildAsync =				0x16,
-  DAC960_CheckConsistency =			0x0F,
-  DAC960_CheckConsistencyAsync =		0x1E,
-  DAC960_RebuildStat =				0x0C,
-  DAC960_GetRebuildProgress =			0x27,
-  DAC960_RebuildControl =			0x1F,
-  DAC960_ReadBadBlockTable =			0x0B,
-  DAC960_ReadBadDataTable =			0x25,
-  DAC960_ClearBadDataTable =			0x26,
-  DAC960_GetErrorTable =			0x17,
-  DAC960_AddCapacityAsync =			0x2A,
-  /* Configuration Related Commands */
-  DAC960_ReadConfig2 =				0x3D,
-  DAC960_WriteConfig2 =				0x3C,
-  DAC960_ReadConfigurationOnDisk =		0x4A,
-  DAC960_WriteConfigurationOnDisk =		0x4B,
-  DAC960_ReadConfiguration =			0x4E,
-  DAC960_ReadBackupConfiguration =		0x4D,
-  DAC960_WriteConfiguration =			0x4F,
-  DAC960_AddConfiguration =			0x4C,
-  DAC960_ReadConfigurationLabel =		0x48,
-  DAC960_WriteConfigurationLabel =		0x49,
-  /* Firmware Upgrade Related Commands */
-  DAC960_LoadImage =				0x20,
-  DAC960_StoreImage =				0x21,
-  DAC960_ProgramImage =				0x22,
-  /* Diagnostic Commands */
-  DAC960_SetDiagnosticMode =			0x31,
-  DAC960_RunDiagnostic =			0x32,
-  /* Subsystem Service Commands */
-  DAC960_GetSubsystemData =			0x70,
-  DAC960_SetSubsystemParameters =		0x71
-}
-__attribute__ ((packed))
-DAC960_CommandOpcode_T;
-
-
-/*
-  Define the DAC960 Command Status Codes.
-*/
-
-#define DAC960_NormalCompletion			0x0000	/* Common */
-#define DAC960_CheckConditionReceived		0x0002	/* Common */
-#define DAC960_NoDeviceAtAddress		0x0102	/* Common */
-#define DAC960_InvalidDeviceAddress		0x0105	/* Common */
-#define DAC960_InvalidParameter			0x0105	/* Common */
-#define DAC960_IrrecoverableDataError		0x0001	/* I/O */
-#define DAC960_LogicalDriveNonexistentOrOffline	0x0002	/* I/O */
-#define DAC960_AccessBeyondEndOfLogicalDrive	0x0105	/* I/O */
-#define DAC960_BadDataEncountered		0x010C	/* I/O */
-#define DAC960_DeviceBusy			0x0008	/* DCDB */
-#define DAC960_DeviceNonresponsive		0x000E	/* DCDB */
-#define DAC960_CommandTerminatedAbnormally	0x000F	/* DCDB */
-#define DAC960_UnableToStartDevice		0x0002	/* Device */
-#define DAC960_InvalidChannelOrTarget		0x0105	/* Device */
-#define DAC960_ChannelBusy			0x0106	/* Device */
-#define DAC960_ChannelNotStopped		0x0002	/* Device */
-#define DAC960_AttemptToRebuildOnlineDrive	0x0002	/* Consistency */
-#define DAC960_RebuildBadBlocksEncountered	0x0003	/* Consistency */
-#define DAC960_NewDiskFailedDuringRebuild	0x0004	/* Consistency */
-#define DAC960_RebuildOrCheckAlreadyInProgress	0x0106	/* Consistency */
-#define DAC960_DependentDiskIsDead		0x0002	/* Consistency */
-#define DAC960_InconsistentBlocksFound		0x0003	/* Consistency */
-#define DAC960_InvalidOrNonredundantLogicalDrive 0x0105	/* Consistency */
-#define DAC960_NoRebuildOrCheckInProgress	0x0105	/* Consistency */
-#define DAC960_RebuildInProgress_DataValid	0x0000	/* Consistency */
-#define DAC960_RebuildFailed_LogicalDriveFailure 0x0002	/* Consistency */
-#define DAC960_RebuildFailed_BadBlocksOnOther	0x0003	/* Consistency */
-#define DAC960_RebuildFailed_NewDriveFailed	0x0004	/* Consistency */
-#define DAC960_RebuildSuccessful		0x0100	/* Consistency */
-#define DAC960_AddCapacityInProgress		0x0004	/* Consistency */
-#define DAC960_AddCapacityFailedOrSuspended	0x00F4	/* Consistency */
-#define DAC960_Config2ChecksumError		0x0002	/* Configuration */
-#define DAC960_ConfigurationSuspended		0x0106	/* Configuration */
-#define DAC960_FailedToConfigureNVRAM		0x0105	/* Configuration */
-#define DAC960_ConfigurationNotSavedStateChange	0x0106	/* Configuration */
-#define DAC960_SubsystemNotInstalled		0x0001	/* Subsystem */
-#define DAC960_SubsystemFailed			0x0002	/* Subsystem */
-#define DAC960_SubsystemBusy			0x0106	/* Subsystem */
-
-typedef unsigned short DAC960_CommandStatus_T;
-
-
-/*
-  Define the Enquiry reply structure.
-*/
-
-typedef struct DAC960_Enquiry
-{
-  unsigned char NumberOfLogicalDrives;			/* Byte 0 */
-  unsigned int :24;					/* Bytes 1-3 */
-  unsigned int LogicalDriveSizes[32];			/* Bytes 4-131 */
-  unsigned short FlashAge;				/* Bytes 132-133 */
-  struct {
-    boolean DeferredWriteError:1;			/* Byte 134 Bit 0 */
-    boolean BatteryLow:1;				/* Byte 134 Bit 1 */
-    unsigned char :6;					/* Byte 134 Bits 2-7 */
-  } StatusFlags;
-  unsigned char :8;					/* Byte 135 */
-  unsigned char MinorFirmwareVersion;			/* Byte 136 */
-  unsigned char MajorFirmwareVersion;			/* Byte 137 */
-  enum {
-    DAC960_NoStandbyRebuildOrCheckInProgress =			0x00,
-    DAC960_StandbyRebuildInProgress =				0x01,
-    DAC960_BackgroundRebuildInProgress =			0x02,
-    DAC960_BackgroundCheckInProgress =				0x03,
-    DAC960_StandbyRebuildCOmpletedWithError =			0xFF,
-    DAC960_BackgroundRebuildOrCheckFailed_DriveFailed =		0xF0,
-    DAC960_BackgroundRebuildOrCheckFailed_LogicalDriveFailed =	0xF1,
-    DAC960_BackgroundRebuildOrCheckFailed_OtherCauses =		0xF2,
-    DAC960_BackgroundRebuildOrCheckSuccessfullyTerminated =	0xF3
-  } __attribute__ ((packed)) RebuildFlag;		/* Byte 138 */
-  unsigned char MaxCommands;				/* Byte 139 */
-  unsigned char OfflineLogicalDriveCount;		/* Byte 140 */
-  unsigned char :8;					/* Byte 141 */
-  unsigned short EventLogSequenceNumber;		/* Bytes 142-143 */
-  unsigned char CriticalLogicalDriveCount;		/* Byte 144 */
-  unsigned int :24;					/* Bytes 145-147 */
-  unsigned char DeadDriveCount;				/* Byte 148 */
-  unsigned char :8;					/* Byte 149 */
-  unsigned char RebuildCount;				/* Byte 150 */
-  struct {
-    unsigned char :3;					/* Byte 151 Bits 0-2 */
-    boolean BatteryBackupUnitPresent:1;			/* Byte 151 Bit 3 */
-    unsigned char :3;					/* Byte 151 Bits 4-6 */
-    unsigned char :1;					/* Byte 151 Bit 7 */
-  } MiscFlags;
-  struct {
-    unsigned char TargetID;
-    unsigned char Channel;
-  } DeadDrives[21];					/* Bytes 152-194 */
-  unsigned char Reserved[62];				/* Bytes 195-255 */
-}
-__attribute__ ((packed))
-DAC960_Enquiry_T;
-
-
-/*
-  Define the Enquiry2 reply structure.
-*/
-
-typedef struct DAC960_Enquiry2
-{
-  struct {
-    enum {
-      DAC960_P_PD_PU =				0x01,
-      DAC960_PL =				0x02,
-      DAC960_PG =				0x10,
-      DAC960_PJ =				0x11,
-      DAC960_PTL_0 =				0x14,
-      DAC960_PTL_1 =				0x16
-    } __attribute__ ((packed)) SubModel;		/* Byte 0 */
-    unsigned char ActualChannels;			/* Byte 1 */
-    enum {
-      DAC960_FiveChannelBoard =			0x01,
-      DAC960_ThreeChannelBoard =		0x02,
-      DAC960_TwoChannelBoard =			0x03,
-      DAC960_ThreeChannelASIC_DAC =		0x04
-    } __attribute__ ((packed)) Model;			/* Byte 2 */
-    enum {
-      DAC960_EISA_Controller =			0x01,
-      DAC960_MicroChannel_Controller =		0x02,
-      DAC960_PCI_Controller =			0x03,
-      DAC960_SCSItoSCSI_Controller =		0x08
-    } __attribute__ ((packed)) ProductFamily;		/* Byte 3 */
-  } HardwareID;						/* Bytes 0-3 */
-  /* MajorVersion.MinorVersion-FirmwareType-TurnID */
-  struct {
-    unsigned char MajorVersion;				/* Byte 4 */
-    unsigned char MinorVersion;				/* Byte 5 */
-    unsigned char TurnID;				/* Byte 6 */
-    char FirmwareType;					/* Byte 7 */
-  } FirmwareID;						/* Bytes 4-7 */
-  unsigned char :8;					/* Byte 8 */
-  unsigned int :24;					/* Bytes 9-11 */
-  unsigned char ConfiguredChannels;			/* Byte 12 */
-  unsigned char ActualChannels;				/* Byte 13 */
-  unsigned char MaxTargets;				/* Byte 14 */
-  unsigned char MaxTags;				/* Byte 15 */
-  unsigned char MaxLogicalDrives;			/* Byte 16 */
-  unsigned char MaxArms;				/* Byte 17 */
-  unsigned char MaxSpans;				/* Byte 18 */
-  unsigned char :8;					/* Byte 19 */
-  unsigned int :32;					/* Bytes 20-23 */
-  unsigned int MemorySize;				/* Bytes 24-27 */
-  unsigned int CacheSize;				/* Bytes 28-31 */
-  unsigned int FlashMemorySize;				/* Bytes 32-35 */
-  unsigned int NonVolatileMemorySize;			/* Bytes 36-39 */
-  struct {
-    enum {
-      DAC960_DRAM =				0x00,
-      DAC960_EDO =				0x01
-    } __attribute__ ((packed)) RamType:3;		/* Byte 40 Bits 0-2 */
-    enum {
-      DAC960_None =				0x00,
-      DAC960_Parity =				0x01,
-      DAC960_ECC =				0x02
-    } __attribute__ ((packed)) ErrorCorrection:3;	/* Byte 40 Bits 3-5 */
-    boolean FastPageMode:1;				/* Byte 40 Bit 6 */
-    boolean LowPowerMemory:1;				/* Byte 40 Bit 7 */
-    unsigned char :8;					/* Bytes 41 */
-  } MemoryType;
-  unsigned short ClockSpeed;				/* Bytes 42-43 */
-  unsigned short MemorySpeed;				/* Bytes 44-45 */
-  unsigned short HardwareSpeed;				/* Bytes 46-47 */
-  unsigned int :32;					/* Bytes 48-51 */
-  unsigned int :32;					/* Bytes 52-55 */
-  unsigned char :8;					/* Byte 56 */
-  unsigned char :8;					/* Byte 57 */
-  unsigned short :16;					/* Bytes 58-59 */
-  unsigned short MaxCommands;				/* Bytes 60-61 */
-  unsigned short MaxScatterGatherEntries;		/* Bytes 62-63 */
-  unsigned short MaxDriveCommands;			/* Bytes 64-65 */
-  unsigned short MaxIODescriptors;			/* Bytes 66-67 */
-  unsigned short MaxCombinedSectors;			/* Bytes 68-69 */
-  unsigned char Latency;				/* Byte 70 */
-  unsigned char :8;					/* Byte 71 */
-  unsigned char SCSITimeout;				/* Byte 72 */
-  unsigned char :8;					/* Byte 73 */
-  unsigned short MinFreeLines;				/* Bytes 74-75 */
-  unsigned int :32;					/* Bytes 76-79 */
-  unsigned int :32;					/* Bytes 80-83 */
-  unsigned char RebuildRateConstant;			/* Byte 84 */
-  unsigned char :8;					/* Byte 85 */
-  unsigned char :8;					/* Byte 86 */
-  unsigned char :8;					/* Byte 87 */
-  unsigned int :32;					/* Bytes 88-91 */
-  unsigned int :32;					/* Bytes 92-95 */
-  unsigned short PhysicalDriveBlockSize;		/* Bytes 96-97 */
-  unsigned short LogicalDriveBlockSize;			/* Bytes 98-99 */
-  unsigned short MaxBlocksPerCommand;			/* Bytes 100-101 */
-  unsigned short BlockFactor;				/* Bytes 102-103 */
-  unsigned short CacheLineSize;				/* Bytes 104-105 */
-  struct {
-    enum {
-      DAC960_Narrow_8bit =			0x00,
-      DAC960_Wide_16bit =			0x01,
-      DAC960_Wide_32bit =			0x02
-    } __attribute__ ((packed)) BusWidth:2;		/* Byte 106 Bits 0-1 */
-    enum {
-      DAC960_Fast =				0x00,
-      DAC960_Ultra =				0x01,
-    } __attribute__ ((packed)) BusSpeed:2;		/* Byte 106 Bits 2-3 */
-    boolean Differential:1;				/* Byte 106 Bit 4 */
-    unsigned char :3;					/* Byte 106 Bits 5-7 */
-  } SCSICapability;
-  unsigned char :8;					/* Byte 107 */
-  unsigned int :32;					/* Bytes 108-111 */
-  unsigned short FirmwareBuildNumber;			/* Bytes 112-113 */
-  enum {
-    DAC960_AEMI =				0x01,
-    DAC960_OEM1 =				0x02,
-    DAC960_OEM2 =				0x04,
-    DAC960_OEM3 =				0x08,
-    DAC960_Conner =				0x10,
-    DAC960_SAFTE =				0x20
-  } __attribute__ ((packed)) FaultManagementType;	/* Byte 114 */
-  unsigned char :8;					/* Byte 115 */
-  struct {
-    boolean Clustering:1;				/* Byte 116 Bit 0 */
-    boolean MylexOnlineRAIDExpansion:1;			/* Byte 116 Bit 1 */
-    unsigned int :30;					/* Bytes 116-119 */
-  } FirmwareFeatures;
-  unsigned int :32;					/* Bytes 120-123 */
-  unsigned int :32;					/* Bytes 124-127 */
-}
-DAC960_Enquiry2_T;
-
-
-/*
-  Define the Get Logical Drive Information reply structure.
-*/
-
-typedef struct DAC960_LogicalDriveInformation
-{
-  unsigned int LogicalDriveSize;			/* Bytes 0-3 */
-  enum {
-    DAC960_LogicalDrive_Online =		0x03,
-    DAC960_LogicalDrive_Critical =		0x04,
-    DAC960_LogicalDrive_Offline =		0xFF
-  } __attribute__ ((packed)) LogicalDriveState;		/* Byte 4 */
-  unsigned char RAIDLevel:7;				/* Byte 5 Bits 0-6 */
-  boolean WriteBack:1;					/* Byte 5 Bit 7 */
-  unsigned int :16;					/* Bytes 6-7 */
-}
-DAC960_LogicalDriveInformation_T;
-
-
-/*
-  Define the Perform Event Log Operation Types.
-*/
-
-typedef enum
-{
-  DAC960_GetEventLogEntry =				0x00
-}
-__attribute__ ((packed))
-DAC960_PerformEventLogOpType_T;
-
-
-/*
-  Define the Get Event Log Entry reply structure.
-*/
-
-typedef struct DAC960_EventLogEntry
-{
-  unsigned char MessageType;				/* Byte 0 */
-  unsigned char MessageLength;				/* Byte 1 */
-  unsigned char TargetID:5;				/* Byte 2 Bits 0-4 */
-  unsigned char Channel:3;				/* Byte 2 Bits 5-7 */
-  unsigned char LogicalUnit:6;				/* Byte 3 Bits 0-5 */
-  unsigned char :2;					/* Byte 3 Bits 6-7 */
-  unsigned short SequenceNumber;			/* Bytes 4-5 */
-  unsigned char ErrorCode:7;				/* Byte 6 Bits 0-6 */
-  boolean Valid:1;					/* Byte 6 Bit 7 */
-  unsigned char SegmentNumber;				/* Byte 7 */
-  unsigned char SenseKey:4;				/* Byte 8 Bits 0-3 */
-  unsigned char :1;					/* Byte 8 Bit 4 */
-  boolean ILI:1;					/* Byte 8 Bit 5 */
-  boolean EOM:1;					/* Byte 8 Bit 6 */
-  boolean Filemark:1;					/* Byte 8 Bit 7 */
-  unsigned char Information[4];				/* Bytes 9-12 */
-  unsigned char AdditionalSenseLength;			/* Byte 13 */
-  unsigned char CommandSpecificInformation[4];		/* Bytes 14-17 */
-  unsigned char AdditionalSenseCode;			/* Byte 18 */
-  unsigned char AdditionalSenseCodeQualifier;		/* Byte 19 */
-  unsigned char Dummy[12];				/* Bytes 20-31 */
-}
-DAC960_EventLogEntry_T;
-
-#define DAC960_EventMessagesCount		13
-
-static char
-  *DAC960_EventMessages[DAC960_EventMessagesCount] =
-     { "killed because write recovery failed",
-       "killed because of SCSI bus reset failure",
-       "killed because of double check condition",
-       "killed because it was removed",
-       "killed because of gross error on SCSI chip",
-       "killed because of bad tag returned from drive",
-       "killed because of timeout on SCSI command",
-       "killed because of reset SCSI command issued from system",
-       "killed because busy or parity error count exceeded limit",
-       "killed because of 'kill drive' command from system",
-       "killed because of selection timeout",
-       "killed due to SCSI phase sequence error",
-       "killed due to unknown status" };
-
-
-/*
-  Define the Get Device State reply structure.
-*/
-
-typedef struct DAC960_DeviceState
-{
-  boolean Present:1;					/* Byte 0 Bit 0 */
-  unsigned char :7;					/* Byte 0 Bits 1-7 */
-  enum {
-    DAC960_OtherType =				0x00,
-    DAC960_DiskType =				0x01,
-    DAC960_SequentialType =			0x02,
-    DAC960_CDROM_or_WORM_Type =			0x03
-    } __attribute__ ((packed)) DeviceType:2;		/* Byte 1 Bits 0-1 */
-  boolean :1;						/* Byte 1 Bit 2 */
-  boolean Fast20:1;					/* Byte 1 Bit 3 */
-  boolean Sync:1;					/* Byte 1 Bit 4 */
-  boolean Fast:1;					/* Byte 1 Bit 5 */
-  boolean Wide:1;					/* Byte 1 Bit 6 */
-  boolean TaggedQueuingSupported:1;			/* Byte 1 Bit 7 */
-  enum {
-    DAC960_Device_Dead =			0x00,
-    DAC960_Device_WriteOnly =			0x02,
-    DAC960_Device_Online =			0x03,
-    DAC960_Device_Standby =			0x10
-  } __attribute__ ((packed)) DeviceState;		/* Byte 2 */
-  unsigned char :8;					/* Byte 3 */
-  unsigned char SynchronousMultiplier;			/* Byte 4 */
-  unsigned char SynchronousOffset:5;			/* Byte 5 Bits 0-4 */
-  unsigned char :3;					/* Byte 5 Bits 5-7 */
-  unsigned long DiskSize __attribute__ ((packed));	/* Bytes 6-9 */
-}
-DAC960_DeviceState_T;
-
-
-/*
-  Define the Get Rebuild Progress reply structure.
-*/
-
-typedef struct DAC960_RebuildProgress
-{
-  unsigned int LogicalDriveNumber;			/* Bytes 0-3 */
-  unsigned int LogicalDriveSize;			/* Bytes 4-7 */
-  unsigned int RemainingBlocks;				/* Bytes 8-11 */
-}
-DAC960_RebuildProgress_T;
-
-
-/*
-  Define the Config2 reply structure.
-*/
-
-typedef struct DAC960_Config2
-{
-  unsigned char :1;					/* Byte 0 Bit 0 */
-  boolean ActiveNegationEnabled:1;			/* Byte 0 Bit 1 */
-  unsigned char :5;					/* Byte 0 Bits 2-6 */
-  boolean NoRescanIfResetReceivedDuringScan:1;		/* Byte 0 Bit 7 */
-  boolean StorageWorksSupportEnabled:1;			/* Byte 1 Bit 0 */
-  boolean HewlettPackardSupportEnabled:1;		/* Byte 1 Bit 1 */
-  boolean NoDisconnectOnFirstCommand:1;			/* Byte 1 Bit 2 */
-  unsigned char :2;					/* Byte 1 Bits 3-4 */
-  boolean AEMI_ARM:1;					/* Byte 1 Bit 5 */
-  boolean AEMI_OFM:1;					/* Byte 1 Bit 6 */
-  unsigned char :1;					/* Byte 1 Bit 7 */
-  enum {
-    DAC960_OEMID_Mylex =			0x00,
-    DAC960_OEMID_IBM =				0x08,
-    DAC960_OEMID_HP =				0x0A,
-    DAC960_OEMID_DEC =				0x0C,
-    DAC960_OEMID_Siemens =			0x10,
-    DAC960_OEMID_Intel =			0x12
-  } __attribute__ ((packed)) OEMID;			/* Byte 2 */
-  unsigned char OEMModelNumber;				/* Byte 3 */
-  unsigned char PhysicalSector;				/* Byte 4 */
-  unsigned char LogicalSector;				/* Byte 5 */
-  unsigned char BlockFactor;				/* Byte 6 */
-  boolean ReadAheadEnabled:1;				/* Byte 7 Bit 0 */
-  boolean LowBIOSDelay:1;				/* Byte 7 Bit 1 */
-  unsigned char :2;					/* Byte 7 Bits 2-3 */
-  boolean ReassignRestrictedToOneSector:1;		/* Byte 7 Bit 4 */
-  unsigned char :1;					/* Byte 7 Bit 5 */
-  boolean ForceUnitAccessDuringWriteRecovery:1;		/* Byte 7 Bit 6 */
-  boolean EnableLeftSymmetricRAID5Algorithm:1;		/* Byte 7 Bit 7 */
-  unsigned char DefaultRebuildRate;			/* Byte 8 */
-  unsigned char :8;					/* Byte 9 */
-  unsigned char BlocksPerCacheLine;			/* Byte 10 */
-  unsigned char BlocksPerStripe;			/* Byte 11 */
-  struct {
-    enum {
-      DAC960_Async =				0x00,
-      DAC960_Sync_8MHz =			0x01,
-      DAC960_Sync_5MHz =			0x02,
-      DAC960_Sync_10or20MHz =			0x03	/* Bits 0-1 */
-    } __attribute__ ((packed)) Speed:2;
-    boolean Force8Bit:1;				/* Bit 2 */
-    boolean DisableFast20:1;				/* Bit 3 */
-    unsigned char :3;					/* Bits 4-6 */
-    boolean EnableTaggedQueuing:1;			/* Bit 7 */
-  } __attribute__ ((packed)) ChannelParameters[6];	/* Bytes 12-17 */
-  unsigned char SCSIInitiatorID;			/* Byte 18 */
-  unsigned char :8;					/* Byte 19 */
-  enum {
-    DAC960_StartupMode_ControllerSpinUp =	0x00,
-    DAC960_StartupMode_PowerOnSpinUp =		0x01
-  } __attribute__ ((packed)) StartupMode;		/* Byte 20 */
-  unsigned char SimultaneousDeviceSpinUpCount;		/* Byte 21 */
-  unsigned char SecondsDelayBetweenSpinUps;		/* Byte 22 */
-  unsigned char Reserved1[29];				/* Bytes 23-51 */
-  boolean BIOSDisabled:1;				/* Byte 52 Bit 0 */
-  boolean CDROMBootEnabled:1;				/* Byte 52 Bit 1 */
-  unsigned char :3;					/* Byte 52 Bits 2-4 */
-  enum {
-    DAC960_Geometry_128_32 =			0x00,
-    DAC960_Geometry_255_63 =			0x01,
-    DAC960_Geometry_Reserved1 =			0x02,
-    DAC960_Geometry_Reserved2 =			0x03
-  } __attribute__ ((packed)) DriveGeometry:2;		/* Byte 52 Bits 5-6 */
-  unsigned char :1;					/* Byte 52 Bit 7 */
-  unsigned char Reserved2[9];				/* Bytes 53-61 */
-  unsigned short Checksum;				/* Bytes 62-63 */
-}
-DAC960_Config2_T;
-
-
-/*
-  Define the Scatter/Gather List Type 1 32 Bit Address 32 Bit Byte Count
-  structure.
-*/
-
-typedef struct DAC960_ScatterGatherSegment
-{
-  DAC960_BusAddress_T SegmentDataPointer;		/* Bytes 0-3 */
-  DAC960_ByteCount_T SegmentByteCount;			/* Bytes 4-7 */
-}
-DAC960_ScatterGatherSegment_T;
-
-
-/*
-  Define the 13 Byte DAC960 Command Mailbox structure.  Bytes 13-15 are
-  not used.  The Command Mailbox structure is padded to 16 bytes for
-  efficient access.
-*/
-
-typedef union DAC960_CommandMailbox
-{
-  unsigned int Words[4];				/* Words 0-3 */
-  unsigned char Bytes[16];				/* Bytes 0-15 */
-  struct {
-    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
-    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
-    unsigned char Dummy[14];				/* Bytes 2-15 */
-  } __attribute__ ((packed)) Common;
-  struct {
-    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
-    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
-    unsigned char Dummy1[6];				/* Bytes 2-7 */
-    DAC960_BusAddress_T BusAddress;			/* Bytes 8-11 */
-    unsigned char Dummy2[4];				/* Bytes 12-15 */
-  } __attribute__ ((packed)) Type3;
-  struct {
-    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
-    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
-    unsigned char Channel;				/* Byte 2 */
-    unsigned char TargetID;				/* Byte 3 */
-    unsigned char Dummy1[4];				/* Bytes 4-7 */
-    DAC960_BusAddress_T BusAddress;			/* Bytes 8-11 */
-    unsigned char Dummy2[4];				/* Bytes 12-15 */
-  } __attribute__ ((packed)) Type3D;
-  struct {
-    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
-    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
-    DAC960_PerformEventLogOpType_T OperationType;	/* Byte 2 */
-    unsigned char OperationQualifier;			/* Byte 3 */
-    unsigned short SequenceNumber;			/* Bytes 4-5 */
-    unsigned char Dummy1[2];				/* Bytes 6-7 */
-    DAC960_BusAddress_T BusAddress;			/* Bytes 8-11 */
-    unsigned char Dummy2[4];				/* Bytes 12-15 */
-  } __attribute__ ((packed)) Type3E;
-  struct {
-    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
-    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
-    struct {
-      unsigned short TransferLength:11;			/* Bytes 2-3 */
-      unsigned char LogicalDriveNumber:5;		/* Byte 3 Bits 3-7 */
-    } __attribute__ ((packed)) LD;
-    unsigned int LogicalBlockAddress;			/* Bytes 4-7 */
-    DAC960_BusAddress_T BusAddress;			/* Bytes 8-11 */
-    unsigned char ScatterGatherCount:6;			/* Byte 12 Bits 0-5 */
-    enum {
-      DAC960_ScatterGather_32BitAddress_32BitByteCount =	0x0,
-      DAC960_ScatterGather_32BitAddress_16BitByteCount =	0x1,
-      DAC960_ScatterGather_32BitByteCount_32BitAddress =	0x2,
-      DAC960_ScatterGather_16BitByteCount_32BitAddress =	0x3
-    } __attribute__ ((packed)) ScatterGatherType:2;	/* Byte 12 Bits 6-7 */
-    unsigned char Dummy[3];				/* Bytes 13-15 */
-  } __attribute__ ((packed)) Type5;
-  struct {
-    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
-    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
-    unsigned char CommandOpcode2;			/* Byte 2 */
-    unsigned char :8;					/* Byte 3 */
-    DAC960_BusAddress_T CommandMailboxesBusAddress;	/* Bytes 4-7 */
-    DAC960_BusAddress_T StatusMailboxesBusAddress;	/* Bytes 8-11 */
-    unsigned char Dummy[4];				/* Bytes 12-15 */
-  } __attribute__ ((packed)) TypeX;
-}
-DAC960_CommandMailbox_T;
-
-
-/*
-  Define the DAC960 V4 Controller Command Mailbox structure.
-*/
-
-typedef DAC960_CommandMailbox_T DAC960_V4_CommandMailbox_T;
-
-
-/*
-  Define the DAC960 V4 Controller Status Mailbox structure.
-*/
-
-typedef union DAC960_V4_StatusMailbox
-{
-  unsigned int Word;					/* Bytes 0-3 */
-  struct {
-    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 0 */
-    unsigned char :7;					/* Byte 1 Bits 0-6 */
-    boolean Valid:1;					/* Byte 1 Bit 7 */
-    DAC960_CommandStatus_T CommandStatus;		/* Bytes 2-3 */
-  } Fields;
-}
-DAC960_V4_StatusMailbox_T;
-
-
-/*
-  Define the DAC960 Driver Command Types.
-*/
-
-typedef enum
-{
-  DAC960_ReadCommand =				1,
-  DAC960_WriteCommand =				2,
-  DAC960_ReadRetryCommand =			3,
-  DAC960_WriteRetryCommand =			4,
-  DAC960_MonitoringCommand =			5,
-  DAC960_ImmediateCommand =			6
-}
-DAC960_CommandType_T;
-
-
-/*
-  Define the DAC960 Driver Command structure.
-*/
-
-typedef struct DAC960_Command
-{
-  DAC960_CommandType_T CommandType;
-  DAC960_CommandMailbox_T CommandMailbox;
-  DAC960_CommandStatus_T CommandStatus;
-  struct DAC960_Controller *Controller;
-  struct DAC960_Command *Next;
-  Semaphore_T *Semaphore;
-  unsigned int LogicalDriveNumber;
-  unsigned int BlockNumber;
-  unsigned int BlockCount;
-  unsigned int SegmentCount;
-  BufferHeader_T *BufferHeader;
-  DAC960_ScatterGatherSegment_T
-    ScatterGatherList[DAC960_MaxScatterGatherSegments];
-}
-DAC960_Command_T;
-
-
-/*
-  Define the DAC960 Driver Controller structure.
-*/
-
-typedef struct DAC960_Controller
-{
-  void *BaseAddress;
-  void *MemoryMappedAddress;
-  DAC960_ControllerType_T ControllerType;
-  DAC960_IO_Address_T IO_Address;
-  DAC960_PCI_Address_T PCI_Address;
-  unsigned char ControllerNumber;
-  unsigned char ModelName[12];
-  unsigned char FullModelName[18];
-  unsigned char FirmwareVersion[14];
-  unsigned char Bus;
-  unsigned char Device;
-  unsigned char Function;
-  unsigned char IRQ_Channel;
-  unsigned char Channels;
-  unsigned char MemorySize;
-  unsigned char LogicalDriveCount;
-  unsigned char GeometryTranslationHeads;
-  unsigned char GeometryTranslationSectors;
-  unsigned short ControllerQueueDepth;
-  unsigned short DriverQueueDepth;
-  unsigned short MaxBlocksPerCommand;
-  unsigned short MaxScatterGatherSegments;
-  unsigned short StripeSize;
-  unsigned short SegmentSize;
-  unsigned short NewEventLogSequenceNumber;
-  unsigned short OldEventLogSequenceNumber;
-  unsigned short MessageBufferLength;
-  unsigned int ControllerUsageCount;
-  unsigned int EnquiryIndex;
-  unsigned int LogicalDriveInformationIndex;
-  unsigned int DeviceStateIndex;
-  unsigned int DeviceStateChannel;
-  unsigned int DeviceStateTargetID;
-  unsigned long SecondaryMonitoringTime;
-  unsigned long RebuildLastReportTime;
-  boolean SAFTE_FaultManagementEnabled;
-  boolean MonitoringCommandDeferred;
-  boolean NeedLogicalDriveInformation;
-  boolean NeedDeviceStateInformation;
-  boolean NeedRebuildProgress;
-  GenericDiskInfo_T GenericDiskInfo;
-  Timer_T MonitoringTimer;
-  DAC960_Command_T *FreeCommands;
-  DAC960_V4_CommandMailbox_T *FirstCommandMailbox;
-  DAC960_V4_CommandMailbox_T *LastCommandMailbox;
-  DAC960_V4_CommandMailbox_T *NextCommandMailbox;
-  DAC960_V4_CommandMailbox_T *PreviousCommandMailbox;
-  DAC960_V4_StatusMailbox_T *FirstStatusMailbox;
-  DAC960_V4_StatusMailbox_T *LastStatusMailbox;
-  DAC960_V4_StatusMailbox_T *NextStatusMailbox;
-  DAC960_Enquiry_T Enquiry[2];
-  DAC960_LogicalDriveInformation_T
-    LogicalDriveInformation[2][DAC960_MaxLogicalDrives];
-  DAC960_DeviceState_T DeviceState[2][DAC960_MaxChannels][DAC960_MaxTargets];
-  DAC960_EventLogEntry_T EventLogEntry;
-  DAC960_RebuildProgress_T RebuildProgress;
-  DAC960_Command_T Commands[DAC960_MaxDriverQueueDepth];
-  DiskPartition_T DiskPartitions[DAC960_MinorCount];
-  int LogicalDriveUsageCount[DAC960_MaxLogicalDrives];
-  int PartitionSizes[DAC960_MinorCount];
-  int BlockSizes[DAC960_MinorCount];
-  int MaxSectorsPerRequest[DAC960_MinorCount];
-  int MaxSegmentsPerRequest[DAC960_MinorCount];
-  char MessageBuffer[DAC960_MessageBufferSize];
-}
-DAC960_Controller_T;
-
-
-/*
-  DAC960_AcquireControllerLock acquires exclusive access to Controller.
-*/
-
-static inline
-void DAC960_AcquireControllerLock(DAC960_Controller_T *Controller,
-				  ProcessorFlags_T *ProcessorFlags)
-{
-  save_flags(*ProcessorFlags);
-  cli();
-}
-
-
-/*
-  DAC960_ReleaseControllerLock releases exclusive access to Controller.
-*/
-
-static inline
-void DAC960_ReleaseControllerLock(DAC960_Controller_T *Controller,
-				  ProcessorFlags_T *ProcessorFlags)
-{
-  restore_flags(*ProcessorFlags);
-}
-
-
-/*
-  DAC960_AcquireControllerLockRF acquires exclusive access to Controller,
-  but is only called from the request function when interrupts are disabled.
-*/
-
-static inline
-void DAC960_AcquireControllerLockRF(DAC960_Controller_T *Controller,
-				    ProcessorFlags_T *ProcessorFlags)
-{
-}
-
-
-/*
-  DAC960_ReleaseControllerLockRF releases exclusive access to Controller,
-  but is only called from the request function when interrupts are disabled.
-*/
-
-static inline
-void DAC960_ReleaseControllerLockRF(DAC960_Controller_T *Controller,
-				    ProcessorFlags_T *ProcessorFlags)
-{
-}
-
-
-/*
-  DAC960_AcquireControllerLockIH acquires exclusive access to Controller,
-  but is only called from the interrupt handler when interrupts are disabled.
-*/
-
-static inline
-void DAC960_AcquireControllerLockIH(DAC960_Controller_T *Controller,
-				    ProcessorFlags_T *ProcessorFlags)
-{
-}
-
-
-/*
-  DAC960_ReleaseControllerLockIH releases exclusive access to Controller,
-  but is only called from the interrupt handler when interrupts are disabled.
-*/
-
-static inline
-void DAC960_ReleaseControllerLockIH(DAC960_Controller_T *Controller,
-				    ProcessorFlags_T *ProcessorFlags)
-{
-}
-
-
-/*
-  Define inline functions to provide an abstraction for reading and writing the
-  DAC960 V4 Controller Interface Registers.
-*/
-
-static inline
-void DAC960_V4_NewCommand(void *ControllerBaseAddress)
-{
-  DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
-  InboundDoorBellRegister.All = 0;
-  InboundDoorBellRegister.Write.NewCommand = true;
-  writel(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_V4_AcknowledgeStatus(void *ControllerBaseAddress)
-{
-  DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
-  InboundDoorBellRegister.All = 0;
-  InboundDoorBellRegister.Write.AcknowledgeStatus = true;
-  writel(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_V4_SoftReset(void *ControllerBaseAddress)
-{
-  DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
-  InboundDoorBellRegister.All = 0;
-  InboundDoorBellRegister.Write.SoftReset = true;
-  writel(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
-}
-
-static inline
-boolean DAC960_V4_MailboxFullP(void *ControllerBaseAddress)
-{
-  DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
-  InboundDoorBellRegister.All =
-    readl(ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
-  return InboundDoorBellRegister.Read.MailboxFull;
-}
-
-static inline
-void DAC960_V4_AcknowledgeInterrupt(void *ControllerBaseAddress)
-{
-  DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister;
-  OutboundDoorBellRegister.All = 0;
-  OutboundDoorBellRegister.Write.AcknowledgeInterrupt = true;
-  writel(OutboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-boolean DAC960_V4_StatusAvailableP(void *ControllerBaseAddress)
-{
-  DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister;
-  OutboundDoorBellRegister.All =
-    readl(ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset);
-  return OutboundDoorBellRegister.Read.StatusAvailable;
-}
-
-static inline
-void DAC960_V4_EnableInterrupts(void *ControllerBaseAddress)
-{
-  DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister;
-  InterruptMaskRegister.All = 0;
-  InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3;
-  InterruptMaskRegister.Bits.DisableInterrupts = false;
-  InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F;
-  writel(InterruptMaskRegister.All,
-	 ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset);
-}
-
-static inline
-void DAC960_V4_DisableInterrupts(void *ControllerBaseAddress)
-{
-  DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister;
-  InterruptMaskRegister.All = 0;
-  InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3;
-  InterruptMaskRegister.Bits.DisableInterrupts = true;
-  InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F;
-  writel(InterruptMaskRegister.All,
-	 ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset);
-}
-
-static inline
-boolean DAC960_V4_InterruptsEnabledP(void *ControllerBaseAddress)
-{
-  DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister;
-  InterruptMaskRegister.All =
-    readl(ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset);
-  return !InterruptMaskRegister.Bits.DisableInterrupts;
-}
-
-static inline
-void DAC960_V4_WriteCommandMailbox(DAC960_CommandMailbox_T *NextCommandMailbox,
-				   DAC960_CommandMailbox_T *CommandMailbox)
-{
-  NextCommandMailbox->Words[1] = CommandMailbox->Words[1];
-  NextCommandMailbox->Words[2] = CommandMailbox->Words[2];
-  NextCommandMailbox->Words[3] = CommandMailbox->Words[3];
-  NextCommandMailbox->Words[0] = CommandMailbox->Words[0];
-}
-
-static inline
-void DAC960_V4_WriteLegacyCommand(void *ControllerBaseAddress,
-				  DAC960_CommandMailbox_T *CommandMailbox)
-{
-  writel(CommandMailbox->Words[0],
-	 ControllerBaseAddress + DAC960_V4_CommandOpcodeRegisterOffset);
-  writel(CommandMailbox->Words[1],
-	 ControllerBaseAddress + DAC960_V4_MailboxRegister4Offset);
-  writel(CommandMailbox->Words[2],
-	 ControllerBaseAddress + DAC960_V4_MailboxRegister8Offset);
-  writeb(CommandMailbox->Bytes[12],
-	 ControllerBaseAddress + DAC960_V4_MailboxRegister12Offset);
-}
-
-static inline DAC960_CommandIdentifier_T
-DAC960_V4_ReadStatusCommandIdentifier(void *ControllerBaseAddress)
-{
-  return readb(ControllerBaseAddress
-	       + DAC960_V4_StatusCommandIdentifierRegOffset);
-}
-
-static inline DAC960_CommandStatus_T
-DAC960_V4_ReadStatusRegister(void *ControllerBaseAddress)
-{
-  return readw(ControllerBaseAddress + DAC960_V4_StatusRegisterOffset);
-}
-
-
-/*
-  Define inline functions to provide an abstraction for reading and writing the
-  DAC960 V3 Controller Interface Registers.
-*/
-
-static inline
-void DAC960_V3_NewCommand(void *ControllerBaseAddress)
-{
-  DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
-  InboundDoorBellRegister.All = 0;
-  InboundDoorBellRegister.Write.NewCommand = true;
-  writeb(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_V3_AcknowledgeStatus(void *ControllerBaseAddress)
-{
-  DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
-  InboundDoorBellRegister.All = 0;
-  InboundDoorBellRegister.Write.AcknowledgeStatus = true;
-  writeb(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
-}
-
-static inline
-void DAC960_V3_SoftReset(void *ControllerBaseAddress)
-{
-  DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
-  InboundDoorBellRegister.All = 0;
-  InboundDoorBellRegister.Write.SoftReset = true;
-  writeb(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
-}
-
-static inline
-boolean DAC960_V3_MailboxFullP(void *ControllerBaseAddress)
-{
-  DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
-  InboundDoorBellRegister.All =
-    readb(ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
-  return InboundDoorBellRegister.Read.MailboxFull;
-}
-
-static inline
-void DAC960_V3_AcknowledgeInterrupt(void *ControllerBaseAddress)
-{
-  DAC960_V3_OutboundDoorBellRegister_T OutboundDoorBellRegister;
-  OutboundDoorBellRegister.All = 0;
-  OutboundDoorBellRegister.Write.AcknowledgeInterrupt = true;
-  writeb(OutboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V3_OutboundDoorBellRegisterOffset);
-}
-
-static inline
-boolean DAC960_V3_StatusAvailableP(void *ControllerBaseAddress)
-{
-  DAC960_V3_OutboundDoorBellRegister_T OutboundDoorBellRegister;
-  OutboundDoorBellRegister.All =
-    readb(ControllerBaseAddress + DAC960_V3_OutboundDoorBellRegisterOffset);
-  return OutboundDoorBellRegister.Read.StatusAvailable;
-}
-
-static inline
-void DAC960_V3_EnableInterrupts(void *ControllerBaseAddress)
-{
-  DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister;
-  InterruptEnableRegister.All = 0;
-  InterruptEnableRegister.Bits.EnableInterrupts = true;
-  writeb(InterruptEnableRegister.All,
-	 ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset);
-}
-
-static inline
-void DAC960_V3_DisableInterrupts(void *ControllerBaseAddress)
-{
-  DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister;
-  InterruptEnableRegister.All = 0;
-  InterruptEnableRegister.Bits.EnableInterrupts = false;
-  writeb(InterruptEnableRegister.All,
-	 ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset);
-}
-
-static inline
-boolean DAC960_V3_InterruptsEnabledP(void *ControllerBaseAddress)
-{
-  DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister;
-  InterruptEnableRegister.All =
-    readb(ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset);
-  return InterruptEnableRegister.Bits.EnableInterrupts;
-}
-
-static inline
-void DAC960_V3_WriteCommandMailbox(void *ControllerBaseAddress,
-				   DAC960_CommandMailbox_T *CommandMailbox)
-{
-  writel(CommandMailbox->Words[0],
-	 ControllerBaseAddress + DAC960_V3_CommandOpcodeRegisterOffset);
-  writel(CommandMailbox->Words[1],
-	 ControllerBaseAddress + DAC960_V3_MailboxRegister4Offset);
-  writel(CommandMailbox->Words[2],
-	 ControllerBaseAddress + DAC960_V3_MailboxRegister8Offset);
-  writeb(CommandMailbox->Bytes[12],
-	 ControllerBaseAddress + DAC960_V3_MailboxRegister12Offset);
-}
-
-static inline DAC960_CommandIdentifier_T
-DAC960_V3_ReadStatusCommandIdentifier(void *ControllerBaseAddress)
-{
-  return readb(ControllerBaseAddress
-	       + DAC960_V3_StatusCommandIdentifierRegOffset);
-}
-
-static inline DAC960_CommandStatus_T
-DAC960_V3_ReadStatusRegister(void *ControllerBaseAddress)
-{
-  return readw(ControllerBaseAddress + DAC960_V3_StatusRegisterOffset);
-}
-
-
-/*
-  Virtual_to_Bus and Bus_to_Virtual map between Kernel Virtual Addresses
-  and PCI Bus Addresses.
-*/
-
-static inline DAC960_BusAddress_T Virtual_to_Bus(void *VirtualAddress)
-{
-  return (DAC960_BusAddress_T) virt_to_bus(VirtualAddress);
-}
-
-static inline void *Bus_to_Virtual(DAC960_BusAddress_T BusAddress)
-{
-  return (void *) bus_to_virt(BusAddress);
-}
-
-
-/*
-  Define compatibility macros between Linux 2.0 and Linux 2.1.
-*/
-
-#if LINUX_VERSION_CODE < 0x20100
-
-#define MODULE_PARM(Variable, Type)
-#define ioremap_nocache(Offset, Size)	vremap(Offset, Size)
-#define iounmap(Address)		vfree(Address)
-
-#endif
-
-
-/*
-  Define prototypes for the forward referenced DAC960 Driver Internal Functions.
-*/
-
-static void DAC960_RequestFunction0(void);
-static void DAC960_RequestFunction1(void);
-static void DAC960_RequestFunction2(void);
-static void DAC960_RequestFunction3(void);
-static void DAC960_RequestFunction4(void);
-static void DAC960_RequestFunction5(void);
-static void DAC960_RequestFunction6(void);
-static void DAC960_RequestFunction7(void);
-static void DAC960_InterruptHandler(int, void *, Registers_T *);
-static void DAC960_QueueMonitoringCommand(DAC960_Command_T *);
-static void DAC960_MonitoringTimerFunction(unsigned long);
-static int DAC960_Open(Inode_T *, File_T *);
-static void DAC960_Release(Inode_T *, File_T *);
-static int DAC960_Ioctl(Inode_T *, File_T *, unsigned int, unsigned long);
-static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *);
-static void DAC960_Message(DAC960_MessageLevel_T, char *,
-			   DAC960_Controller_T *, ...);
-
-
-#endif /* DAC960_DriverVersion */
diff -urN linux-2.0.37-pre3/drivers/scsi/dc390.h linux-2.0.37-pre4/drivers/scsi/dc390.h
--- linux-2.0.37-pre3/drivers/scsi/dc390.h	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/scsi/dc390.h	2003-08-15 15:04:28.000000000 -0700
@@ -4,7 +4,7 @@
  *	Description: Device Driver for Tekram DC-390(T) PCI SCSI       *
  *		     Bus Master Host Adapter			       *
  ***********************************************************************/
-/* $Id: dc390.h,v 2.4 1998/11/05 10:16:42 garloff Exp $ */
+/* $Id: dc390.h,v 2.12 1998/12/25 17:33:27 garloff Exp $ */
 
 #include <linux/version.h>
 
@@ -16,7 +16,7 @@
 #define DC390_H
 
 #define DC390_BANNER "Tekram DC390/AM53C974"
-#define DC390_VERSION "2.0b1 1998/11/05"
+#define DC390_VERSION "2.0d 1998/12/25"
 
 #if defined(HOSTS_C) || defined(MODULE)
 
diff -urN linux-2.0.37-pre3/drivers/scsi/Makefile linux-2.0.37-pre4/drivers/scsi/Makefile
--- linux-2.0.37-pre3/drivers/scsi/Makefile	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/scsi/Makefile	2003-08-15 15:04:28.000000000 -0700
@@ -153,6 +153,7 @@
   endif
 endif
 
+
 ifeq ($(CONFIG_SCSI_INITIO),y)
 L_OBJS += initio.o
 else
diff -urN linux-2.0.37-pre3/drivers/scsi/README.tmscsim linux-2.0.37-pre4/drivers/scsi/README.tmscsim
--- linux-2.0.37-pre3/drivers/scsi/README.tmscsim	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/scsi/README.tmscsim	2003-08-15 15:04:28.000000000 -0700
@@ -45,7 +45,8 @@
 1.12, then 1.20a to 1.20t. Finally I decided to use the ncr53c8xx scheme. So
 the next revisions will be 2.0a to 2.0X (stable), 2.1a to 2.1X (experimental),
 2.2a to 2.2X (stable, again) etc. (X = anything between a and z.) If I send
-fixes to people for testing, those will have a digit appended, e.g. 2.0a1.
+fixes to people for testing, I create intermediate versions with a digit 
+appended, e.g. 2.0c3.
 
 
 2. Installation
@@ -56,32 +57,36 @@
 support into your kernel or as module when configuring your kernel for
 compiling.
 
-If you got an older kernel with an old version of this driver included, you
-should copy the files (dc390.h, tmscsim.h, tmscsim.c, scsiiom.c and
-README.tmscsim) from this directory to linux/drivers/scsi. You have to
-recompile your kernel/module of course.
-
-You should apply the three patches included in dc390-20-kernel.diff
-(Applying them: cd /usr/src; patch -p0 <~/dc390-20-kernel.diff)
-The patches are against 2.1.103, so you might have to manually resolve
-rejections when applying to another kernel version.
-
-The patches will update the kernel startup code to allow boot parameters to
-be passed to the driver, update the Documentation and finally offer you the
-possibility to omit the non-DC390 parts of the driver.
-(By selecting "Omit support for non DC390" you basically disable the
-emulation of a DC390 EEPROM for non DC390 adapters. This saves a few bytes
-of memory.)
+ If you got an old kernel (pre 2.1.127, pre 2.0.37p1) with an old version of
+ this driver: Get dc390-21125-20b.diff.gz or dc390-2036p21-20b1.diff.gz from
+ my website and apply the patch. 
+
+ If you want to do it manually, you should copy the files (dc390.h,
+ tmscsim.h, tmscsim.c, scsiiom.c and README.tmscsim) from this directory to
+ linux/drivers/scsi. You have to recompile your kernel/module of course.
+
+ You should apply the three patches included in dc390-120-kernel.diff
+ (Applying them: cd /usr/src; patch -p0 <~/dc390-120-kernel.diff)
+ The patches are against 2.1.125, so you might have to manually resolve
+ rejections when applying to another kernel version.
+
+ The patches will update the kernel startup code to allow boot parameters to
+ be passed to the driver, update the Documentation and finally offer you the
+ possibility to omit the non-DC390 parts of the driver.
+ (By selecting "Omit support for non DC390" you basically disable the
+ emulation of a DC390 EEPROM for non DC390 adapters. This saves a few bytes
+ of memory.)
 
 If you got a very old kernel without the tmscsim driver (pre 2.0.31)
 I recommend upgrading your kernel. However, if you don't want to, please
 contact me to get the appropriate patches.
 
-Testing a SCSI driver is always a delicate thing to do. The 2.0 driver has
+
+Upgrading a SCSI driver is always a delicate thing to do. The 2.0 driver has
 proven stable on many systems, but it's still a good idea to take some
 precautions. In an ideal world you would have a full backup of your disks.
 The world isn't ideal and most people don't have full backups (me neither).
-So take at least the following two measures:
+So take at least the following measures:
 * make your kernel remount the FS read-only on detecting an error:
   tune2fs -e remount-ro /dev/sd??
 * have copies of your SCSI disk's partition tables on some safe location:
@@ -104,18 +109,19 @@
 3.Features
 ----------
 - SCSI
- * Tagged queueing
+ * Tagged command queueing
  * Sync speed up to 10 MHz
  * Disconnection
  * Multiple LUNs
 
 - General / Linux interface
- * Support for up to 4 adapters.
+ * Support for up to 4 AM53C974 adapters.
  * DC390 EEPROM usage or boot/module params
  * Information via cat /proc/scsi/tmscsim/?
  * Dynamically configurable by writing to /proc/scsi/tmscsim/?
  * Dynamic allocation of resources
- * SMP support: Adapter specific locks (Linux 2.1.x)
+ * SMP support: Locking on io_request lock (Linux 2.1/2.2) or adapter 
+    specific locks (Linux 2.3)
  * Uniform source code for Linux-2.x.y
  * Support for dyn. addition/removal of devices via add/remove-single-device
    (Try: echo "scsi add-single-device H C I L" >/proc/scsi/scsi 
@@ -337,9 +343,7 @@
 
 Further investigation on these problems:
 
-* TagQ and Disconnection (Resel: SRB Tag Seleection)
-* Problems with IRQ sharing (IO-APIC on SMP Systems) (??)
-* Driver crashes with readcdda (xcdroast)
+* Driver hangs with sync readcdda (xcdroast) (most probably VIA PCI error)
 
 Known problems:
 
@@ -363,12 +367,9 @@
   Richard Waltham <dormouse@farsrobt.demon.co.uk> or Doug Ledford
   <dledford@dialnet.net>, if you want to help further debugging it.
 * 2.0.35: CD changers (e.g. NAKAMICHI MBR-7.{0,2}) have problems because
-  the mid-level code doesn't handle BLIST_SINGLELUN correctly. Apply
-  the patch 2035-scsi-singlelun.diff. Thanks to Chiaki Ishikawa.
-  I was told that this fix will be in 2.0.36, so you don't need it for
-  2.0.36. 
-[The patch file is contained in the dc390-XXX.tar.gz files which can be found
-on the ftp server. See below.]
+  the mid-level code doesn't handle BLIST_SINGLELUN correctly. There used
+  to be a patch included here to fix this, but I was told that it is fixed
+  in 2.0.36.
 
 
 7. Bug reports, debugging and updates
@@ -380,7 +381,7 @@
 Please append the output of /proc/scsi/scsi, /proc/scsi/tmscsim/? and
 maybe the DC390 log messages to the report. 
 
-Bug reports should be send to me (Kurt Garloff <K.Garloff@ping.de>) as well
+Bug reports should be send to me (Kurt Garloff <dc390@garloff.de>) as well
 as to the linux-scsi list (<linux-scsi@vger.rutgers.edu>), as sometimes bugs
 are caused by the SCSI mid-level code.
 
@@ -392,7 +393,10 @@
 having your box spending most of its time doing the logging.
 
 The latest version of the driver can be found at:
-ftp://student.physik.uni-dortmund.de/pub/linux/kernel/dc390/
+ http://www.garloff.de/kurt/linux/dc390/
+and
+ ftp://student.physik.uni-dortmund.de/pub/linux/kernel/dc390/
+(The latter might shut down some day.)
 
 
 8. Acknowledgements
@@ -409,6 +413,6 @@
 
 
 -------------------------------------------------------------------------
-Written by Kurt Garloff <K.Garloff@ping.de> 1998/06/11
-Last updated 1998/10/15, driver revision 2.0b
-$Id: README.tmscsim,v 2.5 1998/11/05 10:38:38 garloff Exp $
+Written by Kurt Garloff <kurt@garloff.de> 1998/06/11
+Last updated 1998/12/25, driver revision 2.0d
+$Id: README.tmscsim,v 2.9 1998/12/25 18:04:20 garloff Exp $
diff -urN linux-2.0.37-pre3/drivers/scsi/scsiiom.c linux-2.0.37-pre4/drivers/scsi/scsiiom.c
--- linux-2.0.37-pre3/drivers/scsi/scsiiom.c	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/scsi/scsiiom.c	2003-08-15 15:04:29.000000000 -0700
@@ -4,7 +4,7 @@
  *	Description: Device Driver for Tekram DC-390 (T) PCI SCSI      *
  *		     Bus Master Host Adapter			       *
  ***********************************************************************/
-/* $Id: scsiiom.c,v 2.4 1998/11/05 10:16:43 garloff Exp $ */
+/* $Id: scsiiom.c,v 2.15 1998/12/25 17:33:27 garloff Exp $ */
 
 UCHAR
 dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
@@ -36,7 +36,7 @@
 	    DC390_write8 (ScsiFifo, bval);
 	    bval1 = SEL_W_ATN;
 	    pSRB->SRBState = SRB_START_;
-	    DEBUG1(printk ("DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
+	    DEBUG1(printk (KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
 	    if( pDCB->SyncMode & SYNC_ENABLE )
 		{
 		if( !(pDCB->IdentifyMsg & 7) ||		/* LUN == 0 || Cmd != INQUIRY */
@@ -53,21 +53,21 @@
 	    if(pDCB->SyncMode & EN_TAG_QUEUEING)
 	    {
 	        DC390_write8 (ScsiFifo, MSG_SIMPLE_QTAG);
-		    DEBUG1(printk ("DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN3, pDCB->TagMask);)
+		DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN3, pDCB->TagMask);)
 	        bval = 0; wlval = 1;
 	        while (wlval & pDCB->TagMask)
 		  { bval++; wlval <<= 1; };
 		pDCB->TagMask |= wlval;
 	        DC390_write8 (ScsiFifo, bval);
 		pSRB->TagNumber = bval;
-		DEBUG1(printk ("DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
+		DEBUG1(printk (KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
 		bval1 = SEL_W_ATN3;
 		pSRB->SRBState = SRB_START_;
 	    }
 	    else	/* No TagQ */
 	    {
 		bval1 = SEL_W_ATN;
-		    DEBUG1(printk ("DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
+		DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
 		pSRB->SRBState = SRB_START_;
 	    }
 	}
@@ -82,7 +82,7 @@
 	    bval &= 0xBF;	/* No DisConn */
 	    DC390_write8 (ScsiFifo, bval);
 	    bval1 = SEL_W_ATN;
-	    DEBUG1(printk ("DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
+	    DEBUG1(printk (KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
 	    pSRB->SRBState = SRB_START_;
 	      /* ??? */
 	    if( pDCB->SyncMode & SYNC_ENABLE )
@@ -101,13 +101,13 @@
 	    if(pDCB->SyncMode & EN_TAG_QUEUEING)
 	    {
 		pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG;
-		DEBUG1(printk ("DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN_STOP, pDCB->TagMask);)
+		DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN_STOP, pDCB->TagMask);)
 		bval = 0; wlval = 1;
 	        while (wlval & pDCB->TagMask)
 		  { bval++; wlval <<= 1; };
 		pDCB->TagMask |= wlval;
 		pSRB->TagNumber = bval;
-		DEBUG1(printk ("DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
+		DEBUG1(printk (KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
 		pSRB->MsgOutBuf[1] = bval;
 		pSRB->MsgCnt = 2;
 		bval1 = SEL_W_ATN_STOP;
@@ -119,7 +119,7 @@
 		pSRB->MsgCnt = 1;
 		pSRB->SRBState = SRB_START_;
 		bval1 = SEL_W_ATN_STOP;
-		DEBUG1(printk ("DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
+		DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
 	    };
 	}
     }
@@ -134,7 +134,7 @@
 	    DC390_write8 (ScsiFifo, bval);
 	    DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
 	    DC390_write8 (ScsiFifo, bval);
-	    DEBUG1(printk ("DC390: AutoReqSense !\n");)
+	    DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n");)
 	  }
 	else	/* write cmnd to bus */ 
 	  {
@@ -150,16 +150,16 @@
     {
 	pSRB->SRBState = SRB_READY;
 	pDCB->TagMask &= ~( 1 << pSRB->TagNumber );
-	DEBUG0(printk ("DC390: Interrupt during StartSCSI!\n");)
+	DEBUG0(printk (KERN_WARNING "DC390: Interrupt during StartSCSI!\n");)
 	return 1;
     }
     else
     {
 	pSRB->ScsiPhase = SCSI_NOP1;
 	DEBUG0(if (pACB->pActiveDCB)	\
-		    printk ("DC390: ActiveDCB != 0\n");)
+		    printk (KERN_WARNING "DC390: ActiveDCB != 0\n");)
 	DEBUG0(if (pDCB->pActiveSRB)	\
-		    printk ("DC390: ActiveSRB != 0\n");)
+		    printk (KERN_WARNING "DC390: ActiveSRB != 0\n");)
 	pACB->pActiveDCB = pDCB;
 	pDCB->pActiveSRB = pSRB;
 	//DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
@@ -183,12 +183,10 @@
   DEBUG0(PDEVSET1;)
   DEBUG0(PCI_READ_CONFIG_WORD (PDEV, PCI_STATUS, &pstate);)
   DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY))\
-	{ printk("DC390: PCI state = %04x!\n", pstate); \
+	{ printk(KERN_WARNING "DC390: PCI state = %04x!\n", pstate); \
 	  PCI_WRITE_CONFIG_WORD (PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));};)
 
-  dstate = DC390_read8 (DMA_Status);
-  DC390_write8 (DMA_Status, dstate);	/* clear */
-  //DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);	/* clear */
+  dstate = DC390_read8 (DMA_Status); 
 
   if (! pACB->pActiveDCB || ! pACB->pActiveDCB->pActiveSRB) return dstate;
   else pSRB  = pACB->pActiveDCB->pActiveSRB;
@@ -207,12 +205,11 @@
 	      {
 		DEBUG1(printk (KERN_DEBUG "DC390: read residual bytes ... \n");)
 		dstate = DC390_read8 (DMA_Status);
-		DC390_write8 (DMA_Status, dstate);	/* clear */
 		residual = DC390_read8 (CtcReg_Low) | DC390_read8 (CtcReg_Mid) << 8 |
 		  DC390_read8 (CtcReg_High) << 16;
 		residual += DC390_read8 (Current_Fifo) & 0x1f;
 	      } while (residual && ! (dstate & SCSI_INTERRUPT) && --ctr);
-	    if (!ctr) printk (KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!\n", DC390_read32 (DMA_Wk_ByteCntr));
+	    if (!ctr) printk (KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr));
 	    /* residual =  ... */
 	  }
 	else
@@ -231,6 +228,7 @@
 	
 	DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
     }
+  dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24;
   return dstate;
 };
 #endif
@@ -245,7 +243,9 @@
     UCHAR  phase, i;
     void   (*stateV)( PACB, PSRB, PUCHAR );
     UCHAR  istate, istatus;
+#if DMA_INT
     UCHAR  dstatus;
+#endif
     DC390_AFLAGS DC390_IFLAGS DC390_DFLAGS
 
     pACB = dc390_pACB_start;
@@ -276,7 +276,7 @@
     DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus);)
 
     if( !pACB ) { DC390_UNLOCK_DRV; return; };
-   
+
 #if DMA_INT
     DC390_LOCK_IO;
     DC390_LOCK_ACB;
@@ -284,15 +284,17 @@
     DC390_UNLOCK_ACB;
     DC390_UNLOCK_IO;
 
-    DEBUG1(printk ("dstatus=%02x,", dstatus);)
+    DEBUG1(printk (KERN_DEBUG "dstatus=%02x,", dstatus);)
     if (! (dstatus & SCSI_INTERRUPT))
       {
-	DEBUG0(printk ("DC390 Int w/o SCSI actions (only DMA?)\n");)
+	DEBUG0(printk (KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n");)
 	DC390_UNLOCK_DRV;
 	return;
       };
 #else
-    dstatus = DC390_read8 (DMA_Status);
+    //DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
+    //dstatus = DC390_read8 (DMA_Status);
+    //DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
 #endif
 
     DC390_LOCK_IO;
@@ -302,14 +304,15 @@
     istate = DC390_read8 (Intern_State);
     istatus = DC390_read8 (INT_Status); /* This clears Scsi_Status, Intern_State and INT_Status ! */
 
-    DEBUG1(printk ("Istatus(Res,Inv,Dis,Serv,Succ,ReS,SelA,Sel)=%02x,",istatus);)
-    dc390_laststatus = dstatus<<24 | sstatus<<16 | istate<<8 | istatus;
+    DEBUG1(printk (KERN_INFO "Istatus(Res,Inv,Dis,Serv,Succ,ReS,SelA,Sel)=%02x,",istatus);)
+    dc390_laststatus &= ~0x00ffffff;
+    dc390_laststatus |= /* dstatus<<24 | */ sstatus<<16 | istate<<8 | istatus;
 
     if (sstatus & ILLEGAL_OP_ERR)
-       {
-	       printk ("DC390: Illegal Operation detected (%08lx)!\n", dc390_laststatus);
-	       dc390_dumpinfo (pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB);
-       };
+    {
+	printk ("DC390: Illegal Operation detected (%08lx)!\n", dc390_laststatus);
+	dc390_dumpinfo (pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB);
+    };
 	
     if(istatus &  DISCONNECTED)
     {
@@ -323,18 +326,6 @@
 	goto unlock;
     }
 
-    if(istatus &  INVALID_CMD)
-    {
-	dc390_InvalidCmd( pACB );
-	goto unlock;
-    }
-
-    if(istatus &  SCSI_RESET)
-    {
-	dc390_ScsiRstDetect( pACB );
-	goto unlock;
-    }
-
     if( istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) )
     {
 	pDCB = pACB->pActiveDCB;
@@ -345,7 +336,7 @@
 	};
 	pSRB = pDCB->pActiveSRB;
 	if( pDCB->DCBFlag & ABORT_DEV_ )
-		dc390_EnableMsgOut( pACB, pSRB );
+	  dc390_EnableMsgOut_Abort (pACB, pSRB);
 
 	phase = pSRB->ScsiPhase;
 	DEBUG1(printk (KERN_INFO "DC390: [%i]%s(0) (%02x)\n", phase, dc390_p0_str[phase], sstatus);)
@@ -357,7 +348,21 @@
 	DEBUG1(printk (KERN_INFO "DC390: [%i]%s(1) (%02x)\n", phase, dc390_p1_str[phase], sstatus);)
 	stateV = (void *) dc390_phase1[phase];
 	( *stateV )( pACB, pSRB, &sstatus );
+	goto unlock;
     }
+
+    if(istatus &  INVALID_CMD)
+    {
+	dc390_InvalidCmd( pACB );
+	goto unlock;
+    }
+
+    if(istatus &  SCSI_RESET)
+    {
+	dc390_ScsiRstDetect( pACB );
+	goto unlock;
+    }
+
  unlock:
     DC390_LOCK_DRV_NI;
     DC390_UNLOCK_ACB;
@@ -380,6 +385,7 @@
     UCHAR   sstatus;
     PSGL    psgl;
     ULONG   ResidCnt, xferCnt;
+    UCHAR   dstate = 0;
 
     sstatus = *psstatus;
 
@@ -391,10 +397,9 @@
 	if( sstatus & COUNT_2_ZERO )
 	{
 	    int ctr = 5000000; /* only try for about a tenth of a second */
-	    while( --ctr && !(DC390_read8 (DMA_Status) & DMA_XFER_DONE) && pSRB->SGToBeXferLen )
-		DC390_write8 (DMA_Status,  DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);	/* clear */
-	    if (!ctr) printk (KERN_CRIT "DC390: DataOut_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr));
-	    DC390_write8 (DMA_Status,  DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);	/* clear */
+	    while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen );
+	    if (!ctr) printk (KERN_CRIT "DC390: Deadlock in DataOut_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr));
+	    dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24;
 	    pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
 	    pSRB->SGIndex++;
 	    if( pSRB->SGIndex < pSRB->SGcount )
@@ -443,15 +448,14 @@
 	{
 	    int ctr = 5000000; /* only try for about a tenth of a second */
 	    int dstate = 0;
-	    while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen )
-		DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);	/* clear */
-	    if (!ctr) printk (KERN_CRIT "DC390: DataIn_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr));
+	    while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen );
+	    if (!ctr) printk (KERN_CRIT "DC390: Deadlock in DataIn_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr));
 	    if (!ctr) printk (KERN_CRIT "DC390: DataIn_0: DMA State: %i\n", dstate);
+	    dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24;
 	    DEBUG1(ResidCnt = ((ULONG) DC390_read8 (CtcReg_High) << 16)	\
 		+ ((ULONG) DC390_read8 (CtcReg_Mid) << 8)		\
 		+ ((ULONG) DC390_read8 (CtcReg_Low));)
-	    DEBUG1(printk ("Count_2_Zero (ResidCnt=%li,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);)
-	    DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);	/* clear */
+	    DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%li,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);)
 
 	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
 
@@ -474,7 +478,7 @@
 	    bval = DC390_read8 (Current_Fifo);
 	    while( bval & 0x1f )
 	    {
-		DEBUG1(printk ("Check for residuals,");)
+		DEBUG1(printk (KERN_DEBUG "Check for residuals,");)
 		if( (bval & 0x1f) == 1 )
 		{
 		    for(i=0; i < 0x100; i++)
@@ -494,17 +498,18 @@
 	    }
 din_1:
 	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_BLAST_CMD);
-	    for (i=0; i<0x8000; i++)
+	    for (i = 0xa000; i; i--)
 	    {
 		bval = DC390_read8 (DMA_Status);
-		DC390_write8 (DMA_Status, BLAST_COMPLETE | DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);	/* clear */
 		if (bval & BLAST_COMPLETE)
 		    break;
 	    }
-	    if (i == 0x8000) printk (KERN_CRIT "DC390: DMA Blast aborted unfinished!!\n");
+	    /* It seems a DMA Blast abort isn't that bad ... */
+	    if (!i) printk (KERN_ERR "DC390: DMA Blast aborted unfinished!\n");
 	    //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+	    dc390_laststatus &= ~0xff000000; dc390_laststatus |= bval << 24;
 
-	    DEBUG1(printk ("Blast: Read %i times DMA_Status %02x", i, bval);)
+	    DEBUG1(printk (KERN_DEBUG "Blast: Read %li times DMA_Status %02x", 0xa000-i, bval);)
 	    ResidCnt = (ULONG) DC390_read8 (CtcReg_High);
 	    ResidCnt <<= 8;
 	    ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid);
@@ -525,7 +530,7 @@
 		pSRB->TotalXferredLen++;
 		pSRB->SGToBeXferLen--;
 	    }
-	    DEBUG1(printk ("Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\
+	    DEBUG1(printk (KERN_DEBUG "Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\
 			   pSRB->TotalXferredLen, pSRB->SGToBeXferLen);)
 
 	}
@@ -558,164 +563,278 @@
     //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
 }
 
-void
-dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+
+static void __inline__
+dc390_reprog (PACB pACB, PDCB pDCB)
 {
-    UCHAR  bval;
-    USHORT wval, wval1;
-    PDCB   pDCB;
-    PSRB   psrb;
+  DC390_write8 (Sync_Period, pDCB->SyncPeriod);
+  DC390_write8 (Sync_Offset, pDCB->SyncOffset);
+  DC390_write8 (CtrlReg3, pDCB->CtrlR3);
+  DC390_write8 (CtrlReg4, pDCB->CtrlR4);
+  dc390_SetXferRate (pACB, pDCB);
+};
 
-    pDCB = pACB->pActiveDCB;
 
-    bval = DC390_read8 (ScsiFifo);
-    if( !(pSRB->SRBState & SRB_MSGIN_MULTI) )
+#ifdef DC390_DEBUG0
+static void
+dc390_printMsg (UCHAR *MsgBuf, UCHAR len)
+{
+  int i;
+  printk (" %02x", MsgBuf[0]);
+  for (i = 1; i < len; i++)
+    printk (" %02x", MsgBuf[i]);
+  printk ("\n");
+};
+#endif
+
+#define DC390_ENABLE_MSGOUT DC390_write8 (ScsiCmd, SET_ATN_CMD)
+
+/* reject_msg */
+static void __inline__
+dc390_MsgIn_reject (PACB pACB, PSRB pSRB)
+{
+  pSRB->MsgOutBuf[0] = MSG_REJECT_;
+  pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT;
+  DEBUG0 (printk (KERN_INFO "DC390: Reject message\n");)
+}
+
+/* abort command */
+static void __inline__
+dc390_EnableMsgOut_Abort ( PACB pACB, PSRB pSRB )
+{
+    pSRB->MsgOutBuf[0] = MSG_ABORT; 
+    pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT;
+    pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_;
+}
+
+static PSRB
+dc390_MsgIn_QTag (PACB pACB, PDCB pDCB, UCHAR tag)
+{
+  PSRB lastSRB = pDCB->pGoingLast;
+  PSRB pSRB = pDCB->pGoingSRB;
+
+  if (pSRB)
     {
-	if(bval == MSG_DISCONNECT)
-	{
-	    pSRB->SRBState = SRB_DISCONNECT;
-	}
-	else if( bval == MSG_SAVE_PTR )
-	    goto  min6;
-	else if( (bval == MSG_EXTENDED) || ((bval >= MSG_SIMPLE_QTAG) &&
-					    (bval <= MSG_ORDER_QTAG)) )
+      for( ;pSRB ; )
 	{
-	    pSRB->SRBState |= SRB_MSGIN_MULTI;
-	    pSRB->MsgInBuf[0] = bval;
-	    pSRB->MsgCnt = 1;
-	    pSRB->pMsgPtr = &(pSRB->MsgInBuf[1]);
+	  if (pSRB->TagNumber == tag) break;
+	  if (pSRB == lastSRB) goto mingx0;
+	  pSRB = pSRB->pNextSRB;
 	}
-	else if(bval == MSG_REJECT_)
+
+      if( pDCB->DCBFlag & ABORT_DEV_ )
 	{
-	    DC390_write8 (ScsiCmd, RESET_ATN_CMD);
-	    pDCB->NegoPeriod = 50;
-	    if( pSRB->SRBState & DO_SYNC_NEGO)
-		goto  set_async;
+	  pSRB->SRBState = SRB_ABORT_SENT;
+	  dc390_EnableMsgOut_Abort( pACB, pSRB );
 	}
-	else if( bval == MSG_RESTORE_PTR)
-	    goto  min6;
-	else
-	    goto  min6;
+
+      if( !(pSRB->SRBState & SRB_DISCONNECT) )
+	goto  mingx0;
+
+      pDCB->pActiveSRB = pSRB;
+      pSRB->SRBState = SRB_DATA_XFER;
     }
-    else
-    {	/* minx: */
+  else
+    {
+    mingx0:
+      pSRB = pACB->pTmpSRB;
+      pSRB->SRBState = SRB_UNEXPECT_RESEL;
+      pDCB->pActiveSRB = pSRB;
+      pSRB->MsgOutBuf[0] = MSG_ABORT_TAG;
+      pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT;
+    }
+  return pSRB;
+}
 
-	*pSRB->pMsgPtr = bval;
-	pSRB->MsgCnt++;
-	pSRB->pMsgPtr++;
-	if( (pSRB->MsgInBuf[0] >= MSG_SIMPLE_QTAG) &&
-	    (pSRB->MsgInBuf[0] <= MSG_ORDER_QTAG) )
-	{
-	    if( pSRB->MsgCnt == 2)
-	    {
-		pSRB->SRBState = 0;
-		bval = pSRB->MsgInBuf[1];
-		pSRB = pDCB->pGoingSRB;
-		psrb = pDCB->pGoingLast;
-		if( pSRB )
-		{
-		    for( ;pSRB ; )
-		    {
-			if(pSRB->TagNumber != bval)
-			{
-			    if( pSRB == psrb )
-				goto  mingx0;
-			    pSRB = pSRB->pNextSRB;
-			}
-			else
-			    break;
-		    }
-		    if( pDCB->DCBFlag & ABORT_DEV_ )
-		    {
-			pSRB->SRBState = SRB_ABORT_SENT;
-			dc390_EnableMsgOut( pACB, pSRB );
-		    }
-		    if( !(pSRB->SRBState & SRB_DISCONNECT) )
-			goto  mingx0;
-		    pDCB->pActiveSRB = pSRB;
-		    pSRB->SRBState = SRB_DATA_XFER;
-		}
-		else
-		{
-mingx0:
-		    pSRB = pACB->pTmpSRB;
-		    pSRB->SRBState = SRB_UNEXPECT_RESEL;
-		    pDCB->pActiveSRB = pSRB;
-		    pSRB->MsgOutBuf[0] = MSG_ABORT_TAG;
-		    dc390_EnableMsgOut2( pACB, pSRB );
-		}
-	    }
-	}
-	else if( (pSRB->MsgInBuf[0] == MSG_EXTENDED) && (pSRB->MsgCnt == 5) )
-	{	/* Note: This will fail for target initiated SDTR ? */
-	    pSRB->SRBState &= ~(SRB_MSGIN_MULTI);
-	    if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != EXTENDED_SDTR) )
-	    {	/* reject_msg: */
-		pSRB->MsgCnt = 1;
-		pSRB->MsgInBuf[0] = MSG_REJECT_;
-		DC390_write8 (ScsiCmd, SET_ATN_CMD);
-	    }
-	    else if( !(pSRB->MsgInBuf[3]) || !(pSRB->MsgInBuf[4]) )
-	    {
-set_async:
-		pDCB = pSRB->pSRBDCB;
-		if (!(pSRB->SRBState & DO_SYNC_NEGO)) 
-			printk ("DC390: Target (%i,%i) initiates Non-Sync?\n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
-		pSRB->SRBState &= ~DO_SYNC_NEGO;
-		pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE);
-		pDCB->SyncPeriod = 0;
-		pDCB->SyncOffset = 0;
-		pDCB->CtrlR3 = FAST_CLK;	/* fast clock / normal scsi */
-		pDCB->CtrlR4 &= 0x3f;
-		pDCB->CtrlR4 |= pACB->glitch_cfg;	/* glitch eater */
-		goto re_prog;
-	    }
-	    else
-	    {	/* set_sync: */
 
-		pDCB = pSRB->pSRBDCB;
-		if (!(pSRB->SRBState & DO_SYNC_NEGO)) 
-			printk ("DC390: Target (%i,%i) initiates Sync: %ins %i ?\n", 
-				pDCB->UnitSCSIID, pDCB->UnitSCSILUN, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]);
-		pSRB->SRBState &= ~DO_SYNC_NEGO;
-		pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE;
-		pDCB->SyncOffset &= 0x0f0;
-		pDCB->SyncOffset |= pSRB->MsgInBuf[4];
-		pDCB->NegoPeriod = pSRB->MsgInBuf[3];
-		wval = (USHORT) pSRB->MsgInBuf[3];
-		wval = wval << 2; wval -= 3; wval1 = wval / 25;	/* compute speed */
-		if( (wval1 * 25) != wval)
-		    wval1++;
-		bval = FAST_CLK+FAST_SCSI;	/* fast clock / fast scsi */
-		pDCB->CtrlR4 &= 0x3f;		/* Glitch eater: 12ns less than normal */
-		if (pACB->glitch_cfg != NS_TO_GLITCH(0))
-			pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1));
-		else
-			pDCB->CtrlR4 |= NS_TO_GLITCH(0);
-		if (wval1 < 4) pDCB->CtrlR4 |= NS_TO_GLITCH(0); /* Ultra */
-		if (wval1 >= 8)
-		{
-		    wval1--;	/* Timing computation differs by 1 from FAST_SCSI */
-		    bval = FAST_CLK;		/* fast clock / normal scsi */
-		    pDCB->CtrlR4 |= pACB->glitch_cfg; 	/* glitch eater */
-		}
-		pDCB->CtrlR3 = bval;
-		pDCB->SyncPeriod = (UCHAR)wval1;
-re_prog:
-	        DC390_write8 (Sync_Period, pDCB->SyncPeriod);
-	        DC390_write8 (Sync_Offset, pDCB->SyncOffset);
-	        DC390_write8 (CtrlReg3, pDCB->CtrlR3);
-	        DC390_write8 (CtrlReg4, pDCB->CtrlR4);
-		dc390_SetXferRate (pACB, pDCB);
-	    }
+/* set async transfer mode */
+static void 
+dc390_MsgIn_set_async (PACB pACB, PSRB pSRB)
+{
+  PDCB pDCB = pSRB->pSRBDCB;
+  if (!(pSRB->SRBState & DO_SYNC_NEGO)) 
+    printk ("DC390: Target %i initiates Non-Sync?\n", pDCB->UnitSCSIID);
+  pSRB->SRBState &= ~DO_SYNC_NEGO;
+  pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE);
+  pDCB->SyncPeriod = 0;
+  pDCB->SyncOffset = 0;
+  //pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */
+  pDCB->CtrlR3 = FAST_CLK;	/* fast clock / normal scsi */
+  pDCB->CtrlR4 &= 0x3f;
+  pDCB->CtrlR4 |= pACB->glitch_cfg;	/* glitch eater */
+  dc390_reprog (pACB, pDCB);
+}
+
+/* set sync transfer mode */
+static void
+dc390_MsgIn_set_sync (PACB pACB, PSRB pSRB)
+{
+  UCHAR bval;
+  USHORT wval, wval1;
+  PDCB pDCB = pSRB->pSRBDCB;
+  UCHAR oldsyncperiod = pDCB->SyncPeriod;
+  UCHAR oldsyncoffset = pDCB->SyncOffset;
+  
+  if (!(pSRB->SRBState & DO_SYNC_NEGO))
+    {
+      printk ("DC390: Target %i initiates Sync: %ins %i ... answer ...\n", 
+	      pDCB->UnitSCSIID, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]);
+
+      /* reject */
+      //dc390_MsgIn_reject (pACB, pSRB);
+      //return dc390_MsgIn_set_async (pACB, pSRB);
+
+      /* Reply with corrected SDTR Message */
+      if (pSRB->MsgInBuf[4] > 15)
+	{ 
+	  printk ("DC390: Lower Sync Offset to 15\n");
+	  pSRB->MsgInBuf[4] = 15;
 	}
+      if (pSRB->MsgInBuf[3] < pDCB->NegoPeriod)
+	{
+	  printk ("DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2);
+	  pSRB->MsgInBuf[3] = pDCB->NegoPeriod;
+	};
+      memcpy (pSRB->MsgOutBuf, pSRB->MsgInBuf, 5);
+      pSRB->MsgCnt = 5;
+      DC390_ENABLE_MSGOUT;
+    };
+
+  pSRB->SRBState &= ~DO_SYNC_NEGO;
+  pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE;
+  pDCB->SyncOffset &= 0x0f0;
+  pDCB->SyncOffset |= pSRB->MsgInBuf[4];
+  pDCB->NegoPeriod = pSRB->MsgInBuf[3];
+
+  wval = (USHORT) pSRB->MsgInBuf[3];
+  wval = wval << 2; wval -= 3; wval1 = wval / 25;	/* compute speed */
+  if( (wval1 * 25) != wval) wval1++;
+  bval = FAST_CLK+FAST_SCSI;	/* fast clock / fast scsi */
+
+  pDCB->CtrlR4 &= 0x3f;		/* Glitch eater: 12ns less than normal */
+  if (pACB->glitch_cfg != NS_TO_GLITCH(0))
+    pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1));
+  else
+    pDCB->CtrlR4 |= NS_TO_GLITCH(0);
+  if (wval1 < 4) pDCB->CtrlR4 |= NS_TO_GLITCH(0); /* Ultra */
+
+  if (wval1 >= 8)
+    {
+      wval1--;	/* Timing computation differs by 1 from FAST_SCSI */
+      bval = FAST_CLK;		/* fast clock / normal scsi */
+      pDCB->CtrlR4 |= pACB->glitch_cfg; 	/* glitch eater */
     }
-min6:
+
+  pDCB->CtrlR3 = bval;
+  pDCB->SyncPeriod = (UCHAR)wval1;
+  
+  if ((oldsyncperiod != wval1 || oldsyncoffset != pDCB->SyncOffset) && pDCB->UnitSCSILUN == 0)
+    {
+      if (! (bval & FAST_SCSI)) wval1++;
+      printk ("DC390: Target %i: Sync transfer %i.%1i MHz, Offset %i\n", pDCB->UnitSCSIID, 
+	      40/wval1, ((40%wval1)*10+wval1/2)/wval1, pDCB->SyncOffset & 0x0f);
+    }
+  
+  dc390_reprog (pACB, pDCB);
+};
+
+
+/* According to the docs, the AM53C974 reads the message and 
+ * generates a Succesful Operation IRQ before asserting ACK for
+ * the last byte (how does it know whether it's the last ?) */
+/* The old code handled it in another way, indicating, that on
+ * every message byte an IRQ is generated and every byte has to
+ * be manually ACKed. Hmmm ?  (KG, 98/11/28) */
+/* The old implementation was correct. Sigh! */
+
+/* Check if the message is complete */
+static UCHAR __inline__
+dc390_MsgIn_complete (UCHAR *msgbuf, ULONG len)
+{ 
+  if (*msgbuf == MSG_EXTENDED)
+    {
+      if (len < 2) return 0;
+      if (len < msgbuf[1] + 2) return 0;
+    }
+  else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f) // two byte messages
+    if (len < 2) return 0;
+  return 1;
+}
+
+
+
+/* read and eval received messages */
+void
+dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    PDCB   pDCB = pACB->pActiveDCB;
+
+    /* Read the msg */
+
+    pSRB->MsgInBuf[pACB->MsgLen++] = DC390_read8 (ScsiFifo);
+    //pSRB->SRBState = 0;
+
+    /* Msg complete ? */
+    if (dc390_MsgIn_complete (pSRB->MsgInBuf, pACB->MsgLen))
+      {
+	DEBUG0 (printk (KERN_INFO "DC390: MsgIn:"); dc390_printMsg (pSRB->MsgInBuf, pACB->MsgLen);)
+	/* Now eval the msg */
+	switch (pSRB->MsgInBuf[0]) 
+	  {
+	  case MSG_DISCONNECT: 
+	    pSRB->SRBState = SRB_DISCONNECT; break;
+	    
+	  case MSG_SIMPLE_QTAG:
+	  case MSG_HEAD_QTAG:
+	  case MSG_ORDER_QTAG:
+	    pSRB = dc390_MsgIn_QTag (pACB, pDCB, pSRB->MsgInBuf[1]);
+	    break;
+	    
+	  case MSG_REJECT_: 
+	    DC390_write8 (ScsiCmd, RESET_ATN_CMD);
+	    pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */
+	    if( pSRB->SRBState & DO_SYNC_NEGO)
+	      dc390_MsgIn_set_async (pACB, pSRB);
+	    break;
+	    
+	  case MSG_EXTENDED:
+	    /* reject every extended msg but SDTR */
+	    if (pSRB->MsgInBuf[1] != 3 || pSRB->MsgInBuf[2] != EXTENDED_SDTR)
+	      dc390_MsgIn_reject (pACB, pSRB);
+	    else
+	      {
+		if (pSRB->MsgInBuf[3] == 0 || pSRB->MsgInBuf[4] == 0)
+		  dc390_MsgIn_set_async (pACB, pSRB);
+		else
+		  dc390_MsgIn_set_sync (pACB, pSRB);
+	      };
+	    
+	    // nothing has to be done
+	  case MSG_COMPLETE: break;
+	    
+	    // SAVE POINTER my be ignored as we have the PSRB associated with the
+	    // scsi command. Thanks, Gerard, for pointing it out.
+	  case MSG_SAVE_PTR: break;
+	    // The device might want to restart transfer with a RESTORE
+	  case MSG_RESTORE_PTR: 
+	    printk ("DC390: RESTORE POINTER message received ... reject\n");
+	    // fall through
+
+	    // reject unknown messages
+	  default: dc390_MsgIn_reject (pACB, pSRB);
+	  }
+	
+	/* Clear counter and MsgIn state */
+	pSRB->SRBState &= ~SRB_MSGIN;
+	pACB->MsgLen = 0;
+      };
+
     *psstatus = SCSI_NOP0;
     DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);
     //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
 }
 
+
 void
 dc390_DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir)
 {
@@ -730,10 +849,10 @@
 	    psgl = pSRB->pSegmentList;
 	    pSRB->SGBusAddr = virt_to_bus( psgl->address );
 	    pSRB->SGToBeXferLen = (ULONG) psgl->length;
-	    DEBUG1(printk (" DC390: Next SG segment.");)
+	    DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment.");)
 	}
 	lval = pSRB->SGToBeXferLen;
-	DEBUG1(printk (" DC390: Transfer %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr);)
+	DEBUG1(printk (KERN_DEBUG " DC390: Transfer %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr);)
 	DC390_write8 (CtcReg_Low, (UCHAR) lval);
 	lval >>= 8;
 	DC390_write8 (CtcReg_Mid, (UCHAR) lval);
@@ -749,21 +868,22 @@
 	DC390_write8 (ScsiCmd, DMA_COMMAND+INFO_XFER_CMD);
 
 	DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
-	//DEBUG1(printk ("DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status));)
+	//DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);)
+	//DEBUG1(printk (KERN_DEBUG "DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status));)
+	//DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);)
     }
     else    /* xfer pad */
     {
-	UCHAR bval = 0;
 	if( pSRB->SGcount )
 	{
 	    pSRB->AdaptStatus = H_OVER_UNDER_RUN;
 	    pSRB->SRBStatus |= OVER_RUN;
-	    DEBUG0(printk (" DC390: Overrun -");)
+	    DEBUG0(printk (KERN_WARNING " DC390: Overrun -");)
 	}
-	DEBUG0(printk (" Clear transfer pad \n");)
-	DC390_write8 (CtcReg_Low, bval);
-	DC390_write8 (CtcReg_Mid, bval);
-	DC390_write8 (CtcReg_High, bval);
+	DEBUG0(printk (KERN_WARNING " Clear transfer pad \n");)
+	DC390_write8 (CtcReg_Low, 0);
+	DC390_write8 (CtcReg_Mid, 0);
+	DC390_write8 (CtcReg_High, 0);
 
 	pSRB->SRBState |= SRB_XFERPAD;
 	DC390_write8 (ScsiCmd, DMA_COMMAND+XFER_PAD_BYTE);
@@ -1017,7 +1137,7 @@
 	    dc390_SRBdone( pACB, pDCB, pSRB);
 	}
     }
-    return;
+    pACB->MsgLen = 0;
 }
 
 
@@ -1032,7 +1152,7 @@
     DEBUG0(printk(KERN_INFO "RSEL,");)
     pDCB = pACB->pActiveDCB;
     if( pDCB )
-    {	/* Arbitration lost but Reselection win */
+    {	/* Arbitration lost but Reselection won */
 	DEBUG0(printk ("(ActiveDCB != 0)");)
 	pSRB = pDCB->pActiveSRB;
 	if( !( pACB->scan_devices ) )
@@ -1075,23 +1195,23 @@
 	    printk (KERN_ERR "DC390: Reselect without outstanding cmnd (ID %02x, LUN %02x)\n",
 		    wval & 0xff, (wval & 0xff00) >> 8);
 	    pDCB->pActiveSRB = pSRB;
-	    dc390_EnableMsgOut( pACB, pSRB );
+	    dc390_EnableMsgOut_Abort ( pACB, pSRB );
 	}
 	else
 	{
 	    if( pDCB->DCBFlag & ABORT_DEV_ )
 	    {
 		pSRB->SRBState = SRB_ABORT_SENT;
-		printk (KERN_NOTICE "DC390: Reselect: Abort (ID %02x, LUN %02x)\n",
+		printk (KERN_INFO "DC390: Reselect: Abort (ID %02x, LUN %02x)\n",
 			wval & 0xff, (wval & 0xff00) >> 8);
-		dc390_EnableMsgOut( pACB, pSRB );
+		dc390_EnableMsgOut_Abort( pACB, pSRB );
 	    }
 	    else
 		pSRB->SRBState = SRB_DATA_XFER;
 	}
     }
 
-    DEBUG1(printk ("Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber);)
+    DEBUG1(printk (KERN_DEBUG "Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber);)
     pSRB->ScsiPhase = SCSI_NOP0;
     DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID);
     DC390_write8 (Sync_Period, pDCB->SyncPeriod);
@@ -1244,7 +1364,7 @@
 	    else
 		pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
 				SCSI_STAT_CHECKCOND;
-	    REMOVABLEDEBUG(printk("Cmd=%02x,Result=%08x,XferL=%08x\n",pSRB->CmdBlock[0],\
+	    REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x,Result=%08x,XferL=%08x\n",pSRB->CmdBlock[0],\
 		(UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);)
 	    goto ckc_e;
 	}
@@ -1260,7 +1380,7 @@
 	    {
 		pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) 
 			    | SCSI_STAT_CHECKCOND;
-		REMOVABLEDEBUG(printk("Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->CmdBlock[0],\
+		REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->CmdBlock[0],\
 		       (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);)
 		goto ckc_e;
 	    }
@@ -1299,7 +1419,7 @@
 		    swlval += ptr2->length;
 		    ptr2++;
 		}
-		REMOVABLEDEBUG(printk("XferredLen=%08x,NotXferLen=%08x\n",\
+		REMOVABLEDEBUG(printk(KERN_INFO "XferredLen=%08x,NotXferLen=%08x\n",\
 			(UINT) pSRB->TotalXferredLen, (UINT) swlval);)
 	    }
 	    dc390_RequestSense( pACB, pDCB, pSRB );
@@ -1587,22 +1707,6 @@
 }
 
 
-static void __inline__
-dc390_EnableMsgOut2( PACB pACB, PSRB pSRB )
-{
-    pSRB->MsgCnt = 1;
-    DC390_write8 (ScsiCmd, SET_ATN_CMD);
-}
-
-
-static void __inline__
-dc390_EnableMsgOut( PACB pACB, PSRB pSRB )
-{
-    pSRB->MsgOutBuf[0] = MSG_ABORT;
-    dc390_EnableMsgOut2( pACB, pSRB );
-    pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_;
-}
-
 
 static void __inline__
 dc390_InvalidCmd( PACB pACB )
diff -urN linux-2.0.37-pre3/drivers/scsi/tmscsim.c linux-2.0.37-pre4/drivers/scsi/tmscsim.c
--- linux-2.0.37-pre3/drivers/scsi/tmscsim.c	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/scsi/tmscsim.c	2003-08-15 15:04:29.000000000 -0700
@@ -7,9 +7,9 @@
  ***********************************************************************/
 /* (C) Copyright: put under GNU GPL in 10/96				*
 *************************************************************************/
-/* $Id: tmscsim.c,v 2.5 1998/11/05 10:16:43 garloff Exp $		*/
+/* $Id: tmscsim.c,v 2.16 1998/12/25 17:54:44 garloff Exp $		*/
 /*	Enhancements and bugfixes by					*
- *	Kurt Garloff <K.Garloff@ping.de>				*
+ *	Kurt Garloff <kurt@garloff.de>					*
  ***********************************************************************/
 /*	HISTORY:							*
  *									*
@@ -92,7 +92,11 @@
  *				bios_param() now respects part. table.	*
  *	2.0b  98/10/24	KG	Docu fixes. Timeout Msg in DMA Blast.	*
  *				Disallow illegal idx in INQUIRY/REMOVE	*
- *	2.0b1 98/11/05	KG	Cleaned up detection/initialization	*
+ *	2.0c  98/11/19	KG	Cleaned up detect/init for SMP boxes, 	*
+ *				Write Erase DMA (1.20t) caused problems	*
+ *	2.0d  98/12/25	KG	Christmas release ;-) Message handling  *
+ *				competely reworked. Handle target ini-	*
+ *				tiated SDTR correctly.			*
  ***********************************************************************/
 
 /* Uncomment SA_INTERRUPT, if the driver refuses to share its IRQ with other devices */
@@ -368,9 +372,8 @@
 static void dc390_ScsiRstDetect( PACB pACB );
 static void dc390_ResetSCSIBus( PACB pACB );
 static void __inline__ dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );
-static void __inline__ dc390_EnableMsgOut2( PACB pACB, PSRB pSRB );
-static void __inline__ dc390_EnableMsgOut( PACB pACB, PSRB pSRB );
 static void __inline__ dc390_InvalidCmd( PACB pACB );
+static void __inline__ dc390_EnableMsgOut_Abort (PACB, PSRB);
 static void dc390_remove_dev (PACB pACB, PDCB pDCB);
 void do_DC390_Interrupt( int, void *, struct pt_regs *);
 
@@ -678,7 +681,7 @@
 	pDCB = pDCB->pNextDCB;
 	if (pDCB == pACB->pLinkDCB)
 	  {
-	     printk (KERN_ERR "DC390: DCB not found (DCB=%08x, DCBmap[%2x]=%2x)\n",
+	     printk (KERN_WARNING "DC390: DCB not found (DCB=%08x, DCBmap[%2x]=%2x)\n",
 		     (int)pDCB, cmd->target, pACB->DCBmap[cmd->target]);
 	     return 0;
 	  }
@@ -762,7 +765,7 @@
     UCHAR  bval;
 
     pDCB->GoingSRBCnt--; pDCB->pDCBACB->SelLost++;
-    DEBUG0(printk("DC390: RewaitSRB (%p, %p) pid = %li\n", pDCB, pSRB, pSRB->pcmd->pid);)
+    DEBUG0(printk(KERN_INFO "DC390: RewaitSRB (%p, %p) pid = %li\n", pDCB, pSRB, pSRB->pcmd->pid);)
     psrb1 = pDCB->pGoingSRB;
     if( pSRB == psrb1 )
     {
@@ -989,7 +992,7 @@
 
 
     DEBUG0(/*  if(pACB->scan_devices) */	\
-	printk(KERN_DEBUG "DC390: Queue Cmd=%02x,ID=%d,LUN=%d (pid=%li)\n",\
+	printk(KERN_INFO "DC390: Queue Cmd=%02x,ID=%d,LUN=%d (pid=%li)\n",\
 		cmd->cmnd[0],cmd->target,cmd->lun,cmd->pid);)
 
     DC390_LOCK_ACB;
@@ -1255,15 +1258,17 @@
     printk ("   %02x   %02x   %02x   %02x   %02x   %02x\n",
 	    DC390_read8(INT_Status), DC390_read8(Current_Fifo), DC390_read8(CtrlReg1),
 	    DC390_read8(CtrlReg2), DC390_read8(CtrlReg3), DC390_read8(CtrlReg4));
+    DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
     printk ("DC390: Register dump: DMA engine:\n");
     printk ("DC390: Cmd   STrCnt    SBusA    WrkBC    WrkAC Stat SBusCtrl\n");
     printk ("DC390:  %02x %08x %08x %08x %08x   %02x %08x\n",
 	    DC390_read8(DMA_Cmd), DC390_read32(DMA_XferCnt), DC390_read32(DMA_XferAddr),
 	    DC390_read32(DMA_Wk_ByteCntr), DC390_read32(DMA_Wk_AddrCntr),
 	    DC390_read8(DMA_Status), DC390_read32(DMA_ScsiBusCtrl));
+    DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
     PDEVSET1; PCI_READ_CONFIG_WORD(PDEV, PCI_STATUS, &pstat);
     printk ("DC390: Register dump: PCI Status: %04x\n", pstat);
-    printk ("DC390: Please report driver trouble to K.Garloff@ping.de\n");
+    printk ("DC390: In case of driver trouble read linux/drivers/scsi/README.tmscsim\n");
 };
 
 
@@ -1719,7 +1724,7 @@
     pACB->IOPortBase = (USHORT) io_port;
     pACB->IRQLevel = Irq;
 
-    DEBUG0(printk (KERN_DEBUG "DC390: Adapter index %i, ID %i, IO 0x%08x, IRQ 0x%02x\n",	\
+    DEBUG0(printk (KERN_INFO "DC390: Adapter index %i, ID %i, IO 0x%08x, IRQ 0x%02x\n",	\
 	    index, psh->this_id, (int)io_port, Irq);)
    
     psh->max_id = 8;
@@ -1743,6 +1748,8 @@
     pACB->TagMaxNum = 2 << dc390_eepromBuf[index][EE_TAG_CMD_NUM];
     pACB->ACBFlag = 0;
     pACB->scan_devices = 1;
+    pACB->MsgLen = 0;
+    pACB->Ignore_IRQ = 0;
     pACB->Gmode2 = dc390_eepromBuf[index][EE_MODE2];
     dc390_linkSRB( pACB );
     pACB->pTmpSRB = &pACB->TmpSRB;
@@ -1840,7 +1847,7 @@
 		(dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) ? NEGATE_REQACKDATA : 0);	/* Negation */
     DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
     DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
-    DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
+    DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
     dstate = DC390_read8 (DMA_Status);
     DC390_write8 (DMA_Status, dstate);	/* clear */
 
@@ -1910,8 +1917,8 @@
     }
 #endif
 
-    DEBUG0(printk("DC390: pSH = %8x,", (UINT) psh);)
-    DEBUG0(printk("DC390: Index %02i,", index);)
+    DEBUG0(printk(KERN_INFO "DC390: pSH = %8x,", (UINT) psh);)
+    DEBUG0(printk(" Index %02i,", index);)
 
     dc390_initACB( psh, io_port, Irq, index );
     pACB = (PACB) psh->hostdata;
@@ -1920,7 +1927,7 @@
 
     if( !dc390_initAdapter( psh, io_port, Irq, index ) )
     {
-	DEBUG0(printk("DC390: pACB = %8x, pDCBmap = %8x, pSRB_array = %8x\n",\
+	DEBUG0(printk("\nDC390: pACB = %8x, pDCBmap = %8x, pSRB_array = %8x\n",\
 		(UINT) pACB, (UINT) pACB->DCBmap, (UINT) pACB->SRB_array);)
 	DEBUG0(printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",\
 		sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) );)
@@ -2003,7 +2010,7 @@
 	{
 	    DC390_LOCK_IO;		/* Remove this when going to new eh */
 	    PCI_GET_IO_AND_IRQ;
-	    DEBUG0(printk(KERN_DEBUG "DC390(%i): IO_PORT=%04x,IRQ=%x\n", dc390_adapterCnt, (UINT) io_port, irq);)
+	    DEBUG0(printk(KERN_INFO "DC390(%i): IO_PORT=%04x,IRQ=%x\n", dc390_adapterCnt, (UINT) io_port, irq);)
 
 	    if( !DC390_init(psht, io_port, irq, PDEV, dc390_adapterCnt))
 	    {
@@ -2249,7 +2256,7 @@
       /* NegoPeriod */
       if (*pos != '-')
 	{
-	  SCANF (pos, p0, dum, 76, 800); 
+	  SCANF (pos, p0, dum, 72, 800); 
 	  pDCB->NegoPeriod = dum >> 2;
 	  if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
 	  if (!pos) goto ok;
@@ -2572,7 +2579,7 @@
 	}
 	if (irq_count == 1)
 	 {
-	    DEBUG0(printk(KERN_DEBUG "DC390: Free IRQ %i\n",host->irq);)
+	    DEBUG0(printk(KERN_INFO "DC390: Free IRQ %i\n",host->irq);)
 	    free_irq(host->irq,NULL);
 	 }
     }
diff -urN linux-2.0.37-pre3/drivers/scsi/tmscsim.h linux-2.0.37-pre4/drivers/scsi/tmscsim.h
--- linux-2.0.37-pre3/drivers/scsi/tmscsim.h	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/drivers/scsi/tmscsim.h	2003-08-15 15:04:29.000000000 -0700
@@ -3,7 +3,7 @@
 ;*		    TEKRAM DC-390(T) PCI SCSI Bus Master Host Adapter  *
 ;*		    Device Driver				       *
 ;***********************************************************************/
-/* $Id: tmscsim.h,v 2.1 1998/10/14 10:31:48 garloff Exp $ */
+/* $Id: tmscsim.h,v 2.4 1998/12/25 17:33:27 garloff Exp $ */
 
 #ifndef _TMSCSIM_H
 #define _TMSCSIM_H
@@ -95,15 +95,13 @@
 /* 0x48: */
 SGL		Segmentx;	/* make a one entry of S/G list table */
 
-PUCHAR		pMsgPtr;
-
 UCHAR		ScsiCmdLen;
 UCHAR		ScsiPhase;
 
 UCHAR		AdaptStatus;
 UCHAR		TargetStatus;
 
-/* 0x5c: */
+/* 0x58: */
 UCHAR		MsgCnt;
 UCHAR		EndMessage;
 UCHAR		RetryCnt;
@@ -115,7 +113,7 @@
 UCHAR		SRBStatus;
   //UCHAR		IORBFlag;	/*;81h-Reset, 2-retry */
 
-/* 0x64: */
+/* 0x60: */
 };
 
 
@@ -218,14 +216,16 @@
 UCHAR		sel_timeout;
 UCHAR		glitch_cfg;
 
-UCHAR		reserved[2];	/* alignment */
+UCHAR		MsgLen;
+UCHAR		Ignore_IRQ;	/* Not used */
 
 PDEVDECL1;			/* Pointer to PCI cfg. space */
-/* 0x44/0x40: */
+/* 0x40/0x3c: */
 ULONG		Cmds;
 ULONG		CmdInQ;
 ULONG		CmdOutOfSRB;
 ULONG		SelLost;
+
 	
 /* 0x50/0x4c: */	
 DC390_SRB	TmpSRB;
diff -urN linux-2.0.37-pre3/fs/isofs/inode.c linux-2.0.37-pre4/fs/isofs/inode.c
--- linux-2.0.37-pre3/fs/isofs/inode.c	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/fs/isofs/inode.c	2003-08-15 15:04:29.000000000 -0700
@@ -32,6 +32,13 @@
  */
 #define IGNORE_WRONG_MULTI_VOLUME_SPECS
 
+/*
+ * A home-burnt Joliet level 3 cd-rom with a 100 MB zip file had more than
+ * 100 file sections, so the limit should be larger than that.  What does the
+ * ISO9660 standard say?  (Ulrik Dickow <ukd@kampsax.dk>)
+ */
+#define MAX_FILE_SECTIONS 1000
+
 #ifdef LEAK_CHECK
 static int check_malloc = 0;
 static int check_bread = 0;
@@ -646,8 +653,9 @@
 			nextino = ino->u.isofs_i.i_next_section_ino;
 			iput(ino);
 		
-			if(++i > 100) {
-				printk("isofs_bmap: More than 100 file sections ?!?, aborting...\n");
+			if(++i > MAX_FILE_SECTIONS) {
+				printk("isofs_bmap: More than %d file sections ?!?, aborting...\n",
+				       MAX_FILE_SECTIONS);
 				printk("isofs_bmap: ino=%lu block=%d firstext=%u size=%u nextino=%lu\n",
 				       inode->i_ino, block, firstext, (unsigned)size, nextino);
 				return 0;
@@ -688,9 +696,10 @@
 	ino = inode->i_ino;
 	i = 0;
 	do {
-		if(i > 100) {
-			printk("isofs_read_level3_size: More than 100 file sections ?!?, aborting...\n"
-			       "isofs_read_level3_size: inode=%lu ino=%lu\n", inode->i_ino, ino);
+		if(i > MAX_FILE_SECTIONS) {
+			printk("isofs_read_level3_size: More than %d file sections ?!?, aborting...\n"
+			       "isofs_read_level3_size: inode=%lu ino=%lu\n", MAX_FILE_SECTIONS,
+			       inode->i_ino, ino);
 			return 0;
 		}
 
diff -urN linux-2.0.37-pre3/fs/proc/array.c linux-2.0.37-pre4/fs/proc/array.c
--- linux-2.0.37-pre3/fs/proc/array.c	1998-11-15 10:33:14.000000000 -0800
+++ linux-2.0.37-pre4/fs/proc/array.c	2003-08-15 15:04:29.000000000 -0700
@@ -60,6 +60,7 @@
 int get_malloc(char * buffer);
 #endif
 
+extern unsigned long get_wchan(struct task_struct *);
 
 static int read_core(struct inode * inode, struct file * file,char * buf, int count)
 {
@@ -411,55 +412,6 @@
 	return get_array(p, (*p)->mm->arg_start, (*p)->mm->arg_end, buffer);
 }
 
-unsigned long get_wchan(struct task_struct *p)
-{
-	if (!p || p == current || p->state == TASK_RUNNING)
-		return 0;
-#if defined(__i386__)
-	{
-		unsigned long ebp, eip;
-		unsigned long stack_page;
-		int count = 0;
-
-		stack_page = p->kernel_stack_page;
-		if (!stack_page)
-			return 0;
-		ebp = p->tss.ebp;
-		do {
-			if (ebp < stack_page || ebp >= 4092+stack_page)
-				return 0;
-			eip = *(unsigned long *) (ebp+4);
-			if (eip < (unsigned long) interruptible_sleep_on
-			    || eip >= (unsigned long) add_timer)
-				return eip;
-			ebp = *(unsigned long *) ebp;
-		} while (count++ < 16);
-	}
-#elif defined(__alpha__)
-	/*
-	 * This one depends on the frame size of schedule().  Do a
-	 * "disass schedule" in gdb to find the frame size.  Also, the
-	 * code assumes that sleep_on() follows immediately after
-	 * interruptible_sleep_on() and that add_timer() follows
-	 * immediately after interruptible_sleep().  Ugly, isn't it?
-	 * Maybe adding a wchan field to task_struct would be better,
-	 * after all...
-	 */
-	{
-	    unsigned long schedule_frame;
-	    unsigned long pc;
-
-	    pc = thread_saved_pc(&p->tss);
-	    if (pc >= (unsigned long) interruptible_sleep_on && pc < (unsigned long) add_timer) {
-		schedule_frame = ((unsigned long *)p->tss.ksp)[6];
-		return ((unsigned long *)schedule_frame)[12];
-	    }
-	    return pc;
-	}
-#endif
-	return 0;
-}
-
 #if defined(__i386__)
 # define KSTK_EIP(tsk)	(((unsigned long *)tsk->kernel_stack_page)[1019])
 # define KSTK_ESP(tsk)	(((unsigned long *)tsk->kernel_stack_page)[1022])
diff -urN linux-2.0.37-pre3/include/asm-i386/ioctls.h linux-2.0.37-pre4/include/asm-i386/ioctls.h
--- linux-2.0.37-pre3/include/asm-i386/ioctls.h	1996-07-17 05:10:03.000000000 -0700
+++ linux-2.0.37-pre4/include/asm-i386/ioctls.h	2003-08-15 15:04:29.000000000 -0700
@@ -44,6 +44,8 @@
 #define TIOCGETD	0x5424
 #define TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
 #define TIOCTTYGSTRUCT	0x5426  /* For debugging only */
+#define TIOCSBRK        0x5427  /* BSD compatibility */
+#define TIOCCBRK        0x5428  /* BSD compatibility */
 #define FIONCLEX	0x5450  /* these numbers need to be adjusted. */
 #define FIOCLEX		0x5451
 #define FIOASYNC	0x5452
diff -urN linux-2.0.37-pre3/include/linux/blk.h linux-2.0.37-pre4/include/linux/blk.h
--- linux-2.0.37-pre3/include/linux/blk.h	1998-07-13 13:47:38.000000000 -0700
+++ linux-2.0.37-pre4/include/linux/blk.h	2003-08-15 15:04:29.000000000 -0700
@@ -310,6 +310,16 @@
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
 
+#elif (MAJOR_NR == COMPAQ_SMART2_MAJOR)
+
+#define DEVICE_NAME "ida"
+#define DEVICE_INTR do_ida
+#define TIMEOUT_VALUE (25*HZ)
+#define DEVICE_REQUEST do_ida_request0
+#define DEVICE_NR(device) (MINOR(device) >> 4)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
 #endif /* MAJOR_NR == whatever */
 
 #if (MAJOR_NR != SCSI_TAPE_MAJOR)
@@ -370,7 +380,7 @@
 /* end_request() - SCSI devices have their own version */
 /*               - IDE drivers have their own copy too */
 
-#if ! SCSI_BLK_MAJOR(MAJOR_NR)
+#if ! SCSI_BLK_MAJOR(MAJOR_NR) && (MAJOR_NR != COMPAQ_SMART2_MAJOR)
 
 #if defined(IDE_DRIVER) && !defined(_IDE_C) /* shared copy for IDE modules */
 void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup);
diff -urN linux-2.0.37-pre3/include/linux/hdreg.h linux-2.0.37-pre4/include/linux/hdreg.h
--- linux-2.0.37-pre3/include/linux/hdreg.h	1998-06-03 15:17:49.000000000 -0700
+++ linux-2.0.37-pre4/include/linux/hdreg.h	2003-08-15 15:04:29.000000000 -0700
@@ -92,11 +92,12 @@
 #define HDIO_GETGEO		0x0301	/* get device geometry */
 #define HDIO_GET_UNMASKINTR	0x0302	/* get current unmask setting */
 #define HDIO_GET_MULTCOUNT	0x0304	/* get current IDE blockmode setting */
-#define HDIO_GET_IDENTITY 	0x0307	/* get IDE identification info */
+#define HDIO_OBSOLETE_IDENTITY	0x0307	/* OBSOLETE, DO NOT USE: returns 142 bytes */
 #define HDIO_GET_KEEPSETTINGS 	0x0308	/* get keep-settings-on-reset flag */
 #define HDIO_GET_32BIT 		0x0309	/* get current io_32bit setting */
 #define HDIO_GET_NOWERR		0x030a	/* get ignore-write-error flag */
 #define HDIO_GET_DMA		0x030b	/* get use-dma flag */
+#define HDIO_GET_IDENTITY	0x030d	/* get IDE identification info */
 #define HDIO_DRIVE_CMD		0x031f	/* execute a special drive command */
 
 /* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x032n/0x033n */
@@ -166,14 +167,54 @@
 	unsigned short  word79;
 	unsigned short  word80;
 	unsigned short  word81;
-	unsigned short  word82;
-	unsigned short  word83;
+	unsigned short  command_sets;	/* bits 0:Smart 1:Security 2:Removable 3:PM */
+	unsigned short  word83;		/* bits 14:Smart Enabled 13:0 zero */
 	unsigned short  word84;
 	unsigned short  word85;
 	unsigned short  word86;
 	unsigned short  word87;
 	unsigned short  dma_ultra;
-	unsigned short  reserved[167];
+	unsigned short	word89;		/* reserved (word 89) */
+	unsigned short	word90;		/* reserved (word 90) */
+	unsigned short	word91;		/* reserved (word 91) */
+	unsigned short	word92;		/* reserved (word 92) */
+	unsigned short	word93;		/* reserved (word 93) */
+	unsigned short	word94;		/* reserved (word 94) */
+	unsigned short	word95;		/* reserved (word 95) */
+	unsigned short	word96;		/* reserved (word 96) */
+	unsigned short	word97;		/* reserved (word 97) */
+	unsigned short	word98;		/* reserved (word 98) */
+	unsigned short	word99;		/* reserved (word 99) */
+	unsigned short	word100;	/* reserved (word 100) */
+	unsigned short	word101;	/* reserved (word 101) */
+	unsigned short	word102;	/* reserved (word 102) */
+	unsigned short	word103;	/* reserved (word 103) */
+	unsigned short	word104;	/* reserved (word 104) */
+	unsigned short	word105;	/* reserved (word 105) */
+	unsigned short	word106;	/* reserved (word 106) */
+	unsigned short	word107;	/* reserved (word 107) */
+	unsigned short	word108;	/* reserved (word 108) */
+	unsigned short	word109;	/* reserved (word 109) */
+	unsigned short	word110;	/* reserved (word 110) */
+	unsigned short	word111;	/* reserved (word 111) */
+	unsigned short	word112;	/* reserved (word 112) */
+	unsigned short	word113;	/* reserved (word 113) */
+	unsigned short	word114;	/* reserved (word 114) */
+	unsigned short	word115;	/* reserved (word 115) */
+	unsigned short	word116;	/* reserved (word 116) */
+	unsigned short	word117;	/* reserved (word 117) */
+	unsigned short	word118;	/* reserved (word 118) */
+	unsigned short	word119;	/* reserved (word 119) */
+	unsigned short	word120;	/* reserved (word 120) */
+	unsigned short	word121;	/* reserved (word 121) */
+	unsigned short	word122;	/* reserved (word 122) */
+	unsigned short	word123;	/* reserved (word 123) */
+	unsigned short	word124;	/* reserved (word 124) */
+	unsigned short	word125;	/* reserved (word 125) */
+	unsigned short	word126;	/* reserved (word 126) */
+	unsigned short	word127;	/* reserved (word 127) */
+	unsigned short	security;	/* bits 0:suuport 1:enabled 2:locked 3:frozen */
+	unsigned short	reserved[127];
 };
 
 #ifdef __KERNEL__
diff -urN linux-2.0.37-pre3/include/linux/major.h linux-2.0.37-pre4/include/linux/major.h
--- linux-2.0.37-pre3/include/linux/major.h	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/include/linux/major.h	2003-08-15 15:04:29.000000000 -0700
@@ -71,6 +71,15 @@
 #define APBLOCK_MAJOR   60   /* AP1000 Block device */
 #define DDV_MAJOR       61   /* AP1000 DDV block device */
 
+#define COMPAQ_SMART2_MAJOR	72
+#define COMPAQ_SMART2_MAJOR1	73
+#define COMPAQ_SMART2_MAJOR2	74
+#define COMPAQ_SMART2_MAJOR3	75
+#define COMPAQ_SMART2_MAJOR4	76
+#define COMPAQ_SMART2_MAJOR5	77
+#define COMPAQ_SMART2_MAJOR6	78
+#define COMPAQ_SMART2_MAJOR7	79
+
 #define SPECIALIX_NORMAL_MAJOR 75
 #define SPECIALIX_CALLOUT_MAJOR 76
 
diff -urN linux-2.0.37-pre3/include/linux/pci.h linux-2.0.37-pre4/include/linux/pci.h
--- linux-2.0.37-pre3/include/linux/pci.h	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/include/linux/pci.h	2003-08-15 15:04:29.000000000 -0700
@@ -655,6 +655,9 @@
 #define PCI_DEVICE_ID_INIT_320P		0x9100
 #define PCI_DEVICE_ID_INIT_360P		0x9500
 
+#define PCI_VENDOR_ID_TTI		0x1103
+#define PCI_DEVICE_ID_TTI_HPT343	0x0003
+
 #define PCI_VENDOR_ID_VIA		0x1106
 #define PCI_DEVICE_ID_VIA_82C505	0x0505
 #define PCI_DEVICE_ID_VIA_82C561	0x0561
@@ -959,6 +962,7 @@
 #define PCI_DEVICE_ID_ADAPTEC_7850	0x5078
 #define PCI_DEVICE_ID_ADAPTEC_7855	0x5578
 #define PCI_DEVICE_ID_ADAPTEC_5800	0x5800
+#define PCI_DEVICE_ID_ADAPTEC_1480A 0x6075
 #define PCI_DEVICE_ID_ADAPTEC_7860	0x6078
 #define PCI_DEVICE_ID_ADAPTEC_7861	0x6178
 #define PCI_DEVICE_ID_ADAPTEC_7870	0x7078
@@ -978,6 +982,7 @@
 #define PCI_DEVICE_ID_ADAPTEC2_2940U2	0x0010
 #define PCI_DEVICE_ID_ADAPTEC2_7890	0x001f
 #define PCI_DEVICE_ID_ADAPTEC2_3940U2	0x0050
+#define PCI_DEVICE_ID_ADAPTEC2_3950U2D	0x0051
 #define PCI_DEVICE_ID_ADAPTEC2_7896	0x005f
 
 #define PCI_VENDOR_ID_ATRONICS		0x907f
diff -urN linux-2.0.37-pre3/include/linux/tasks.h linux-2.0.37-pre4/include/linux/tasks.h
--- linux-2.0.37-pre3/include/linux/tasks.h	1995-10-30 00:00:21.000000000 -0800
+++ linux-2.0.37-pre4/include/linux/tasks.h	2003-08-15 15:04:29.000000000 -0700
@@ -11,7 +11,7 @@
 #define NR_CPUS 1
 #endif
 
-#define NR_TASKS	512
+#define NR_TASKS	512	/* Max 4092, or 4090 w/APM configured on x86 */
 
 #define MAX_TASKS_PER_USER (NR_TASKS/2)
 #define MIN_TASKS_LEFT_FOR_ROOT 4
diff -urN linux-2.0.37-pre3/include/linux/via_ide_dma.h linux-2.0.37-pre4/include/linux/via_ide_dma.h
--- linux-2.0.37-pre3/include/linux/via_ide_dma.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.0.37-pre4/include/linux/via_ide_dma.h	2003-08-15 15:04:29.000000000 -0700
@@ -0,0 +1,162 @@
+/* Via Apollo timings display header file for triton.c.
+   Copyright (c) 1998 Michel Aubry 
+*/
+
+typedef char *PCHAR;
+
+static int via_get_info(char *, char **, off_t, int, int);
+static PCHAR print_apollo_drive_config(char *buf,byte bus, byte fn);
+static PCHAR print_apollo_ide_config(char *buf, byte bus, byte fn);
+static PCHAR print_apollo_chipset_control1(char *buf,byte bus, byte fn);
+static PCHAR print_apollo_chipset_control2(char *p,byte bus, byte fn);
+static PCHAR print_apollo_chipset_control3(char *p, byte bus, byte fn, unsigned short n);
+
+static struct proc_dir_entry via_proc_entry = {
+  0, 3, "via", S_IFREG | S_IRUGO, 1, 0, 0, 0, 0, via_get_info
+};
+
+/* we save bus, function of chipset here for further debug use */
+static byte bmide_bus, bmide_fn;
+
+static char *FIFO_str[] = {" 1 ", "3/4", "1/2", "1/4"};
+static char *control3_str[] = {"No limitation", "64","128","192"};
+ 
+static int via_get_info(char *buffer, char **addr, off_t offset, int count, int dummy)
+{
+   /* print what /proc/via displays, if required from DISPLAY_APOLLO_TIMINGS */
+     char *p = buffer;
+     /* Parameter of chipset : */
+     /* Miscellaneous control 1 */
+     p = print_apollo_chipset_control1(buffer,bmide_bus, bmide_fn);
+     /* Miscellaneous control 2 */
+     p = print_apollo_chipset_control2(p,bmide_bus, bmide_fn);
+     /* Parameters of drives: */
+     /* Header */
+     p += sprintf(p,"------------------Primary IDE------------Secondary IDE-----\n");
+     p = print_apollo_chipset_control3(p, bmide_bus, bmide_fn, 0);
+     p = print_apollo_ide_config(p,bmide_bus, bmide_fn);
+     p += sprintf(p,"--------------drive0------drive1-------drive0------drive1----\n");
+     p = print_apollo_chipset_control3(p, bmide_bus, bmide_fn, 1);
+     p = print_apollo_drive_config(p,bmide_bus, bmide_fn);
+ 
+     return p-buffer; /* hoping it is less than 4K... */
+}
+ 
+static PCHAR print_apollo_drive_config(char *buf,byte bus, byte fn)
+{
+     int rc;
+     unsigned int time;
+     byte tm;
+     char *p = buf;  
+ 
+     /*  printk("--------------drive0------drive1-------drive0------drive1----");*/
+ 
+     /* Drive Timing Control */
+ 
+     rc = pcibios_read_config_dword(bus, fn, 0x48, &time);
+     p += sprintf(p,"Act Pls Width:  %02d          %02d           %02d          %02d\n",((time & 0xf0000000)>>28)+1,((time & 0xf00000)>>20)+1,((time & 0xf000)>>12)+1, ((time & 0xf0)>>4)+1);
+     p += sprintf(p,"Recovery Time:  %02d          %02d           %02d          %02d\n",((time & 0x0f000000)>>24)+1, ((time & 0x0f0000)>>16)+1, ((time & 0x0f00)>>8)+1, (time & 0x0f)+1);
+ 
+     /* Address Setup Time */
+ 
+     rc = pcibios_read_config_byte(bus, fn, 0x4C, &tm);
+     p += sprintf(p, "Add. Setup T.:  %01dT          %01dT           %01dT          %01dT\n",((tm & 0xc0)>>6) + 1,((tm & 0x30)>>4) + 1,((tm & 0x0c)>>2) + 1,(tm & 0x03) + 1);
+ 
+     /* UltraDMA33 Extended Timing Control */
+ 
+     rc = pcibios_read_config_dword(bus, fn, 0x50, &time);
+     p += sprintf(p, "------------------UDMA-Timing-Control------------------------\n");
+     p += sprintf(p, "Enable Meth.:    %01d           %01d            %01d           %01d\n",(time & 0x80000000)?1:0,(time & 0x800000)?1:0, (time & 0x8000)?1:0, (time & 0x80)?1:0);
+     p += sprintf(p, "Enable:         %s         %s          %s         %s\n",(time & 0x40000000)?"yes":"no ", (time & 0x400000)?"yes":"no ",(time & 0x4000)?"yes":"no ",(time & 0x40)?"yes":"no ");
+     p += sprintf(p, "Transfer Mode: %s         %s          %s         %s\n",(time & 0x20000000)?"PIO":"DMA",(time & 0x200000)?"PIO":"DMA",(time & 0x2000)?"PIO":"DMA",(time & 0x20)?"PIO":"DMA");
+     p += sprintf(p, "Cycle Time:     %01dT          %01dT           %01dT          %01dT\n",((time & 0x03000000)>>24)+2,((time & 0x030000)>>16)+2,((time & 0x0300)>>8)+2,(time & 0x03)+2);
+ 
+     return (PCHAR)p;
+}
+ 
+static PCHAR print_apollo_ide_config(char *buf, byte bus, byte fn)
+{
+     byte time, tmp; 
+     unsigned short size0,size1;
+     int rc;
+     char *p = buf;  
+ 
+     rc = pcibios_read_config_byte(bus, fn, 0x41, &time);
+     p += sprintf(p,"Prefetch Buffer :      %s                     %s\n", (time & 128)?"on ":"off", (time & 32)?"on ":"off");
+     p += sprintf(p,"Post Write Buffer:     %s                     %s\n", (time & 64)? "on ": "off",(time & 16)?"on ":"off");
+ 
+     /* FIFO configuration */
+     rc = pcibios_read_config_byte(bus, fn, 0x43, &time);
+     tmp = ((time & 0x20)>>2) + ((time & 0x40)>>3);
+     p += sprintf(p,"FIFO Conf/Chan. :      %02d                      %02d\n", 16 - tmp, tmp);
+     tmp = (time & 0x0F)>>2;
+     p += sprintf(p,"Threshold Prim. :      %s                     %s\n", FIFO_str[tmp],FIFO_str[time & 0x03]);
+ 
+     /* chipset Control3 */
+     rc = pcibios_read_config_byte(bus, fn, 0x46, &time);
+     p += sprintf(p,"Read DMA FIFO flush:   %s                     %s\n",(time & 0x80)?"on ":"off", (time & 0x40)?"on ":"off");
+     p += sprintf(p,"End Sect. FIFO flush:  %s                     %s\n",(time & 0x20)?"on ":"off", (time & 0x10)?"on ":"off");
+     p += sprintf(p,"Max DRDY Pulse Width:  %s %s\n", control3_str[(time & 0x03)], (time & 0x03)? "PCI clocks":"");
+ 
+     /* Primary and Secondary sector sizes */
+     rc = pcibios_read_config_word(bus, fn, 0x60, &size0);
+     rc = pcibios_read_config_word(bus, fn, 0x68, &size1);
+     p += sprintf(p,"Bytes Per Sector:      %03d                     %03d\n",size0 & 0xfff,size1 & 0xfff);
+     return (PCHAR)p;
+}
+
+static PCHAR print_apollo_chipset_control1(char *buf,byte bus, byte fn)
+{
+     byte t;
+     int rc;
+     char *p = buf;  
+     unsigned short c;
+     byte l,l_max;   
+ 
+     rc = pcibios_read_config_word(bus, fn, 0x04, &c);
+     rc = pcibios_read_config_byte(bus, fn, 0x44, &t);
+     rc = pcibios_read_config_byte(bus, fn, 0x0d, &l);
+     rc = pcibios_read_config_byte(bus, fn, 0x3f, &l_max);
+     p += sprintf(p,"Command register = 0x%x\n",c);
+     p += sprintf(p,"Master Read  Cycle IRDY %d Wait State\n", (t & 64)>>6);
+     p += sprintf(p,"Master Write Cycle IRDY %d Wait State\n", (t & 32)>>5 );
+     p += sprintf(p,"FIFO Output Data 1/2 Clock Advance: %s\n", (t & 16)? "on ":"off");
+     p += sprintf(p,"Bus Master IDE Status Register Read Retry: %s\n", (t & 8)? "on " : "off");
+     p += sprintf(p,"Latency timer = %d (max. = %d)\n",l,l_max);
+     return (PCHAR)p;
+}
+ 
+static PCHAR print_apollo_chipset_control2(char *buf,byte bus, byte fn)
+{
+     byte t;
+     int rc;
+     char *p = buf;  
+     rc = pcibios_read_config_byte(bus, fn, 0x45, &t);
+     p += sprintf(p,"Interrupt Steering Swap: %s\n", (t & 64)? "on ":"off");
+     return (PCHAR)p;
+}
+ 
+static PCHAR print_apollo_chipset_control3(char *buf, byte bus, byte fn, unsigned short n)
+{
+     /* at that point we can be sure that register 0x20 of the chipset contains the right address... */
+     unsigned int bibma;
+     int rc;
+     byte c0,c1;    
+     char *p = buf; 
+ 
+     rc = pcibios_read_config_dword(bus, fn, 0x20, &bibma);
+     bibma = (bibma & 0xfff0) ;
+ 
+     /* at that point bibma+0x2 et bibma+0xa are byte registers to investigate:*/
+     c0 = inb((unsigned short)bibma + 0x02);
+     c1 = inb((unsigned short)bibma + 0x0a);
+ 
+     if(n==0)
+        /*p = sprintf(p,"--------------------Primary IDE------------Secondary IDE-----");*/
+        p += sprintf(p,"both channels togth:   %s                     %s\n",(c0&0x80)?"no":"yes",(c1&0x80)?"no":"yes");
+     else
+        /*p = sprintf(p,"--------------drive0------drive1-------drive0------drive1----");*/
+        p += sprintf(p,"DMA enabled:    %s         %s          %s         %s\n",(c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ",(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no ");
+ 
+     return (PCHAR)p;
+}
diff -urN linux-2.0.37-pre3/kernel/ksyms.c linux-2.0.37-pre4/kernel/ksyms.c
--- linux-2.0.37-pre3/kernel/ksyms.c	1998-11-15 10:33:20.000000000 -0800
+++ linux-2.0.37-pre4/kernel/ksyms.c	2003-08-15 15:04:29.000000000 -0700
@@ -201,6 +201,8 @@
 	X(hardsect_size),
 	X(blk_size),
 	X(blk_dev),
+	X(max_sectors),
+	X(max_segments),
 	X(is_read_only),
 	X(set_device_ro),
 	X(bmap),
diff -urN linux-2.0.37-pre3/kernel/sched.c linux-2.0.37-pre4/kernel/sched.c
--- linux-2.0.37-pre3/kernel/sched.c	1998-11-15 10:33:20.000000000 -0800
+++ linux-2.0.37-pre4/kernel/sched.c	2003-08-15 15:04:29.000000000 -0700
@@ -87,7 +87,6 @@
 #define _S(nr) (1<<((nr)-1))
 
 extern void mem_use(void);
-extern unsigned long get_wchan(struct task_struct *);
 
 static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
 unsigned long init_user_stack[1024] = { STACK_MAGIC, };
@@ -1667,6 +1666,56 @@
 	return 0;
 }
 
+/* Used in fs/proc/array.c */
+unsigned long get_wchan(struct task_struct *p)
+{
+	if (!p || p == current || p->state == TASK_RUNNING)
+		return 0;
+#if defined(__i386__)
+	{
+		unsigned long ebp, eip;
+		unsigned long stack_page;
+		int count = 0;
+
+		stack_page = p->kernel_stack_page;
+		if (!stack_page)
+			return 0;
+		ebp = p->tss.ebp;
+		do {
+			if (ebp < stack_page || ebp >= 4092+stack_page)
+				return 0;
+			eip = *(unsigned long *) (ebp+4);
+			if (eip < (unsigned long) interruptible_sleep_on
+			    || eip >= (unsigned long) add_timer)
+				return eip;
+			ebp = *(unsigned long *) ebp;
+		} while (count++ < 16);
+	}
+#elif defined(__alpha__)
+	/*
+	 * This one depends on the frame size of schedule().  Do a
+	 * "disass schedule" in gdb to find the frame size.  Also, the
+	 * code assumes that sleep_on() follows immediately after
+	 * interruptible_sleep_on() and that add_timer() follows
+	 * immediately after interruptible_sleep().  Ugly, isn't it?
+	 * Maybe adding a wchan field to task_struct would be better,
+	 * after all...
+	 */
+	{
+	    unsigned long schedule_frame;
+	    unsigned long pc;
+
+	    pc = thread_saved_pc(&p->tss);
+	    if (pc >= (unsigned long) interruptible_sleep_on && pc < (unsigned long) add_timer) {
+		schedule_frame = ((unsigned long *)p->tss.ksp)[6];
+		return ((unsigned long *)schedule_frame)[12];
+	    }
+	    return pc;
+	}
+#endif
+	return 0;
+}
+
 static void show_task(int nr,struct task_struct * p)
 {
 	unsigned long free;
diff -urN linux-2.0.37-pre3/MAINTAINERS linux-2.0.37-pre4/MAINTAINERS
--- linux-2.0.37-pre3/MAINTAINERS	2003-08-15 15:04:28.000000000 -0700
+++ linux-2.0.37-pre4/MAINTAINERS	2003-08-15 15:04:28.000000000 -0700
@@ -172,8 +172,8 @@
 
 DC390/AM53C974 SCSI driver
 P:	Kurt Garloff
-M:	K.Garloff@ping.de
-W:	ftp://student.physik.uni-dortmund.de/pub/linux/kernel/dc390/
+M:	kurt@garloff.de
+W:	http://www.garloff.de/kurt/linux/dc390/
 S:	Maintained
 
 DAC960 RAID DRIVER
@@ -182,6 +182,18 @@
 L:	linux-raid@vger.rutgers.edu
 S:	Maintained
 
+COMPAQ SMART2 RAID DRIVER
+P:	Chris Frantz
+M:	Chris Frantz <arrays@compaq.com>
+L:	linux-raid@vger.rutgers.edu
+S:	Maintained
+
+COMPAQ SMART2 RAID DRIVER
+P:	Chris Frantz
+M:	Chris Frantz <arrays@compaq.com>
+L:	linux-raid@vger.rutgers.edu
+S:	Maintained
+
 EATA ISA/EISA/PCI SCSI DRIVER
 P:	Dario Ballabio
 M:	dario@milano.europe.dg.com
diff -urN linux-2.0.37-pre3/Makefile linux-2.0.37-pre4/Makefile
--- linux-2.0.37-pre3/Makefile	1998-11-15 10:32:44.000000000 -0800
+++ linux-2.0.37-pre4/Makefile	2003-08-15 15:04:28.000000000 -0700
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 0
-SUBLEVEL = 36
+SUBLEVEL = 37
 
 ARCH = i386
 
